@0xmonaco/core 0.6.2 → 0.7.0
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/dist/api/auth/api.d.ts +9 -8
- package/dist/api/auth/api.js +9 -11
- package/dist/api/index.d.ts +3 -0
- package/dist/api/index.js +3 -0
- package/dist/api/margin-accounts/api.d.ts +12 -0
- package/dist/api/margin-accounts/api.js +69 -0
- package/dist/api/margin-accounts/index.d.ts +1 -0
- package/dist/api/margin-accounts/index.js +1 -0
- package/dist/api/market/api.d.ts +8 -1
- package/dist/api/market/api.js +31 -3
- package/dist/api/orderbook/api.js +1 -1
- package/dist/api/perp/index.d.ts +1 -0
- package/dist/api/perp/index.js +1 -0
- package/dist/api/perp/routes.d.ts +133 -0
- package/dist/api/perp/routes.js +85 -0
- package/dist/api/positions/api.d.ts +12 -0
- package/dist/api/positions/api.js +88 -0
- package/dist/api/positions/index.d.ts +1 -0
- package/dist/api/positions/index.js +1 -0
- package/dist/api/trades/api.d.ts +1 -1
- package/dist/api/trades/api.js +2 -2
- package/dist/api/trading/api.d.ts +14 -3
- package/dist/api/trading/api.js +76 -15
- package/dist/api/websocket/types.d.ts +3 -1
- package/dist/api/websocket/websocket.js +153 -17
- package/dist/sdk.d.ts +7 -5
- package/dist/sdk.js +17 -9
- package/package.json +1 -1
- package/dist/api/applications/api.d.ts.map +0 -1
- package/dist/api/applications/api.js.map +0 -1
- package/dist/api/applications/index.d.ts.map +0 -1
- package/dist/api/applications/index.js.map +0 -1
- package/dist/api/auth/api.d.ts.map +0 -1
- package/dist/api/auth/api.js.map +0 -1
- package/dist/api/auth/index.d.ts.map +0 -1
- package/dist/api/auth/index.js.map +0 -1
- package/dist/api/base.d.ts.map +0 -1
- package/dist/api/base.js.map +0 -1
- package/dist/api/fees/api.d.ts.map +0 -1
- package/dist/api/fees/api.js.map +0 -1
- package/dist/api/fees/index.d.ts.map +0 -1
- package/dist/api/fees/index.js.map +0 -1
- package/dist/api/index.d.ts.map +0 -1
- package/dist/api/index.js.map +0 -1
- package/dist/api/market/api.d.ts.map +0 -1
- package/dist/api/market/api.js.map +0 -1
- package/dist/api/market/index.d.ts.map +0 -1
- package/dist/api/market/index.js.map +0 -1
- package/dist/api/orderbook/api.d.ts.map +0 -1
- package/dist/api/orderbook/api.js.map +0 -1
- package/dist/api/orderbook/index.d.ts.map +0 -1
- package/dist/api/orderbook/index.js.map +0 -1
- package/dist/api/profile/api.d.ts.map +0 -1
- package/dist/api/profile/api.js.map +0 -1
- package/dist/api/profile/index.d.ts.map +0 -1
- package/dist/api/profile/index.js.map +0 -1
- package/dist/api/trades/api.d.ts.map +0 -1
- package/dist/api/trades/api.js.map +0 -1
- package/dist/api/trades/index.d.ts.map +0 -1
- package/dist/api/trades/index.js.map +0 -1
- package/dist/api/trading/api.d.ts.map +0 -1
- package/dist/api/trading/api.js.map +0 -1
- package/dist/api/trading/index.d.ts.map +0 -1
- package/dist/api/trading/index.js.map +0 -1
- package/dist/api/vault/api.d.ts.map +0 -1
- package/dist/api/vault/api.js.map +0 -1
- package/dist/api/vault/index.d.ts.map +0 -1
- package/dist/api/vault/index.js.map +0 -1
- package/dist/api/websocket/index.d.ts.map +0 -1
- package/dist/api/websocket/index.js.map +0 -1
- package/dist/api/websocket/types.d.ts.map +0 -1
- package/dist/api/websocket/types.js.map +0 -1
- package/dist/api/websocket/utils.d.ts.map +0 -1
- package/dist/api/websocket/utils.js.map +0 -1
- package/dist/api/websocket/websocket.d.ts.map +0 -1
- package/dist/api/websocket/websocket.js.map +0 -1
- package/dist/errors/errors.d.ts.map +0 -1
- package/dist/errors/errors.js.map +0 -1
- package/dist/errors/index.d.ts.map +0 -1
- package/dist/errors/index.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/networks/index.d.ts.map +0 -1
- package/dist/networks/index.js.map +0 -1
- package/dist/networks/networks.d.ts.map +0 -1
- package/dist/networks/networks.js.map +0 -1
- package/dist/sdk.d.ts.map +0 -1
- package/dist/sdk.js.map +0 -1
- package/dist/utils/index.d.ts.map +0 -1
- package/dist/utils/index.js.map +0 -1
- package/dist/utils/magnitude.d.ts.map +0 -1
- package/dist/utils/magnitude.js.map +0 -1
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
* );
|
|
22
22
|
* ```
|
|
23
23
|
*/
|
|
24
|
-
import type { BatchCancelOrdersResponse, BatchCreateOrderParams, BatchCreateOrdersResponse, BatchReplaceOrderParams, BatchReplaceOrdersResponse, CancelOrderResponse, CreateOrderResponse, GetOrderResponse, GetPaginatedOrdersParams, GetPaginatedOrdersResponse, OrderSide, ReplaceOrderResponse, TimeInForce, TradingAPI, TradingMode } from "@0xmonaco/types";
|
|
24
|
+
import type { BatchCancelOrdersResponse, BatchCreateOrderParams, BatchCreateOrdersResponse, BatchReplaceOrderParams, BatchReplaceOrdersResponse, CancelConditionalOrderResponse, CancelOrderResponse, CreateConditionalOrderParams, CreateConditionalOrderResponse, CreateOrderResponse, GetOrderResponse, GetPaginatedOrdersParams, GetPaginatedOrdersResponse, ListConditionalOrdersParams, ListConditionalOrdersResponse, OrderSide, PositionSide, ReplaceOrderResponse, TimeInForce, TradingAPI, TradingMode } from "@0xmonaco/types";
|
|
25
25
|
import { BaseAPI } from "../base";
|
|
26
26
|
export declare class TradingAPIImpl extends BaseAPI implements TradingAPI {
|
|
27
27
|
/**
|
|
@@ -79,6 +79,10 @@ export declare class TradingAPIImpl extends BaseAPI implements TradingAPI {
|
|
|
79
79
|
useMasterBalance?: boolean;
|
|
80
80
|
expirationDate?: string;
|
|
81
81
|
timeInForce?: TimeInForce;
|
|
82
|
+
marginAccountId?: string;
|
|
83
|
+
positionSide?: PositionSide;
|
|
84
|
+
leverage?: string;
|
|
85
|
+
reduceOnly?: boolean;
|
|
82
86
|
}): Promise<CreateOrderResponse>;
|
|
83
87
|
/**
|
|
84
88
|
* Places a market order for immediate execution.
|
|
@@ -124,6 +128,10 @@ export declare class TradingAPIImpl extends BaseAPI implements TradingAPI {
|
|
|
124
128
|
placeMarketOrder(tradingPairId: string, side: OrderSide, quantity: string, options?: {
|
|
125
129
|
tradingMode?: TradingMode;
|
|
126
130
|
slippageTolerance?: number;
|
|
131
|
+
marginAccountId?: string;
|
|
132
|
+
positionSide?: PositionSide;
|
|
133
|
+
leverage?: string;
|
|
134
|
+
reduceOnly?: boolean;
|
|
127
135
|
}): Promise<CreateOrderResponse>;
|
|
128
136
|
/**
|
|
129
137
|
* Cancels an existing order.
|
|
@@ -142,6 +150,9 @@ export declare class TradingAPIImpl extends BaseAPI implements TradingAPI {
|
|
|
142
150
|
* ```
|
|
143
151
|
*/
|
|
144
152
|
cancelOrder(orderId: string): Promise<CancelOrderResponse>;
|
|
153
|
+
createConditionalOrder(params: CreateConditionalOrderParams): Promise<CreateConditionalOrderResponse>;
|
|
154
|
+
cancelConditionalOrder(conditionalOrderId: string): Promise<CancelConditionalOrderResponse>;
|
|
155
|
+
listConditionalOrders(params?: ListConditionalOrdersParams): Promise<ListConditionalOrdersResponse>;
|
|
145
156
|
/**
|
|
146
157
|
* Batch cancels specific orders by their IDs.
|
|
147
158
|
*
|
|
@@ -242,7 +253,7 @@ export declare class TradingAPIImpl extends BaseAPI implements TradingAPI {
|
|
|
242
253
|
*
|
|
243
254
|
* @param params - Query parameters for filtering orders
|
|
244
255
|
* @param params.status - Filter by order status (e.g., "SUBMITTED", "FILLED") (optional)
|
|
245
|
-
* @param params.
|
|
256
|
+
* @param params.trading_pair_id - Filter by trading pair UUID (optional)
|
|
246
257
|
* @param params.page - Page number for pagination (defaults to 1, must be > 0)
|
|
247
258
|
* @param params.page_size - Number of orders per page (defaults to 10, max 100, must be > 0)
|
|
248
259
|
* @returns Promise resolving to GetPaginatedOrdersResponse with orders and pagination info
|
|
@@ -253,7 +264,7 @@ export declare class TradingAPIImpl extends BaseAPI implements TradingAPI {
|
|
|
253
264
|
* // Get submitted orders for a specific trading pair with custom pagination
|
|
254
265
|
* const orders = await tradingAPI.getPaginatedOrders({
|
|
255
266
|
* status: "SUBMITTED",
|
|
256
|
-
*
|
|
267
|
+
* trading_pair_id: "456e7890-e12b-12d3-a456-426614174000",
|
|
257
268
|
* page: 1,
|
|
258
269
|
* page_size: 20
|
|
259
270
|
* });
|
package/dist/api/trading/api.js
CHANGED
|
@@ -21,8 +21,9 @@
|
|
|
21
21
|
* );
|
|
22
22
|
* ```
|
|
23
23
|
*/
|
|
24
|
-
import { BatchCreateOrdersSchema, BatchReplaceOrdersSchema, CancelOrderSchema, GetPaginatedOrdersSchema, PlaceLimitOrderSchema, PlaceMarketOrderSchema, ReplaceOrderSchema, validate, } from "@0xmonaco/types";
|
|
24
|
+
import { BatchCreateOrdersSchema, BatchReplaceOrdersSchema, CancelConditionalOrderSchema, CancelOrderSchema, CreateConditionalOrderSchema, GetPaginatedOrdersSchema, ListConditionalOrdersSchema, PlaceLimitOrderSchema, PlaceMarketOrderSchema, ReplaceOrderSchema, validate, } from "@0xmonaco/types";
|
|
25
25
|
import { BaseAPI } from "../base";
|
|
26
|
+
import { perpRoutes } from "../perp";
|
|
26
27
|
export class TradingAPIImpl extends BaseAPI {
|
|
27
28
|
/**
|
|
28
29
|
* Places a limit order on the order book.
|
|
@@ -93,8 +94,12 @@ export class TradingAPIImpl extends BaseAPI {
|
|
|
93
94
|
use_master_balance: options?.useMasterBalance,
|
|
94
95
|
expiration_date: options?.expirationDate,
|
|
95
96
|
time_in_force: options?.timeInForce,
|
|
97
|
+
margin_account_id: options?.marginAccountId,
|
|
98
|
+
position_side: options?.positionSide,
|
|
99
|
+
leverage: options?.leverage,
|
|
100
|
+
reduce_only: options?.reduceOnly,
|
|
96
101
|
};
|
|
97
|
-
return await this.makeAuthenticatedRequest(
|
|
102
|
+
return await this.makeAuthenticatedRequest(perpRoutes.orders.create(), {
|
|
98
103
|
method: "POST",
|
|
99
104
|
body: JSON.stringify(requestBody),
|
|
100
105
|
});
|
|
@@ -156,8 +161,12 @@ export class TradingAPIImpl extends BaseAPI {
|
|
|
156
161
|
price: null, // Market orders don't need price
|
|
157
162
|
quantity,
|
|
158
163
|
trading_mode: options?.tradingMode || "SPOT",
|
|
164
|
+
margin_account_id: options?.marginAccountId,
|
|
165
|
+
position_side: options?.positionSide,
|
|
166
|
+
leverage: options?.leverage,
|
|
167
|
+
reduce_only: options?.reduceOnly,
|
|
159
168
|
};
|
|
160
|
-
return await this.makeAuthenticatedRequest(
|
|
169
|
+
return await this.makeAuthenticatedRequest(perpRoutes.orders.create(), {
|
|
161
170
|
method: "POST",
|
|
162
171
|
body: JSON.stringify(requestBody),
|
|
163
172
|
});
|
|
@@ -184,11 +193,53 @@ export class TradingAPIImpl extends BaseAPI {
|
|
|
184
193
|
const requestBody = {
|
|
185
194
|
order_id: orderId,
|
|
186
195
|
};
|
|
187
|
-
return await this.makeAuthenticatedRequest(
|
|
196
|
+
return await this.makeAuthenticatedRequest(perpRoutes.orders.cancel(), {
|
|
188
197
|
method: "POST",
|
|
189
198
|
body: JSON.stringify(requestBody),
|
|
190
199
|
});
|
|
191
200
|
}
|
|
201
|
+
async createConditionalOrder(params) {
|
|
202
|
+
validate(CreateConditionalOrderSchema, params);
|
|
203
|
+
const requestBody = {
|
|
204
|
+
trading_pair_id: params.tradingPairId,
|
|
205
|
+
margin_account_id: params.marginAccountId,
|
|
206
|
+
condition_type: params.conditionType,
|
|
207
|
+
trigger_price: params.triggerPrice,
|
|
208
|
+
trigger_source: params.triggerSource ?? "MARK_PRICE",
|
|
209
|
+
side: params.side,
|
|
210
|
+
position_side: params.positionSide,
|
|
211
|
+
order_type: params.orderType,
|
|
212
|
+
limit_price: params.limitPrice,
|
|
213
|
+
quantity: params.quantity,
|
|
214
|
+
reduce_only: params.reduceOnly ?? true,
|
|
215
|
+
time_in_force: params.timeInForce,
|
|
216
|
+
slippage_tolerance_bps: params.slippageToleranceBps,
|
|
217
|
+
expires_at: params.expiresAt,
|
|
218
|
+
};
|
|
219
|
+
return await this.makeAuthenticatedRequest(perpRoutes.orders.createConditional(), {
|
|
220
|
+
method: "POST",
|
|
221
|
+
body: JSON.stringify(requestBody),
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
async cancelConditionalOrder(conditionalOrderId) {
|
|
225
|
+
validate(CancelConditionalOrderSchema, { conditionalOrderId });
|
|
226
|
+
return await this.makeAuthenticatedRequest(perpRoutes.orders.cancelConditional(conditionalOrderId), {
|
|
227
|
+
method: "DELETE",
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
async listConditionalOrders(params) {
|
|
231
|
+
if (params) {
|
|
232
|
+
validate(ListConditionalOrdersSchema, params);
|
|
233
|
+
}
|
|
234
|
+
const { page = 1, page_size = 20, margin_account_id, trading_pair_id, state } = params || {};
|
|
235
|
+
return await this.makeAuthenticatedRequest(perpRoutes.orders.listConditional({
|
|
236
|
+
page,
|
|
237
|
+
page_size: Math.min(Math.max(page_size, 1), 100),
|
|
238
|
+
margin_account_id,
|
|
239
|
+
trading_pair_id,
|
|
240
|
+
state,
|
|
241
|
+
}), { method: "GET" });
|
|
242
|
+
}
|
|
192
243
|
/**
|
|
193
244
|
* Batch cancels specific orders by their IDs.
|
|
194
245
|
*
|
|
@@ -205,7 +256,7 @@ export class TradingAPIImpl extends BaseAPI {
|
|
|
205
256
|
if (!orderIds || orderIds.length === 0) {
|
|
206
257
|
throw new Error("orderIds is required and must not be empty");
|
|
207
258
|
}
|
|
208
|
-
return this.makeAuthenticatedRequest(
|
|
259
|
+
return this.makeAuthenticatedRequest(perpRoutes.orders.batchCancel(), {
|
|
209
260
|
method: "POST",
|
|
210
261
|
body: JSON.stringify({ order_ids: orderIds }),
|
|
211
262
|
});
|
|
@@ -227,7 +278,7 @@ export class TradingAPIImpl extends BaseAPI {
|
|
|
227
278
|
* ```
|
|
228
279
|
*/
|
|
229
280
|
async batchCancelAll(tradingPairId) {
|
|
230
|
-
const endpoint = tradingPairId ?
|
|
281
|
+
const endpoint = tradingPairId ? perpRoutes.orders.batchCancelAllByPair(tradingPairId) : perpRoutes.orders.batchCancelAll();
|
|
231
282
|
return this.makeAuthenticatedRequest(endpoint, {
|
|
232
283
|
method: "POST",
|
|
233
284
|
});
|
|
@@ -244,7 +295,7 @@ export class TradingAPIImpl extends BaseAPI {
|
|
|
244
295
|
if (newOrder.quantity !== undefined) {
|
|
245
296
|
requestBody.quantity = newOrder.quantity;
|
|
246
297
|
}
|
|
247
|
-
return await this.makeAuthenticatedRequest(
|
|
298
|
+
return await this.makeAuthenticatedRequest(perpRoutes.orders.replace(orderId), {
|
|
248
299
|
method: "PUT",
|
|
249
300
|
body: JSON.stringify(requestBody),
|
|
250
301
|
});
|
|
@@ -293,9 +344,13 @@ export class TradingAPIImpl extends BaseAPI {
|
|
|
293
344
|
use_master_balance: order.useMasterBalance,
|
|
294
345
|
expiration_date: order.expirationDate,
|
|
295
346
|
time_in_force: order.timeInForce,
|
|
347
|
+
margin_account_id: order.marginAccountId,
|
|
348
|
+
position_side: order.positionSide,
|
|
349
|
+
leverage: order.leverage,
|
|
350
|
+
reduce_only: order.reduceOnly,
|
|
296
351
|
})),
|
|
297
352
|
};
|
|
298
|
-
return this.makeAuthenticatedRequest(
|
|
353
|
+
return this.makeAuthenticatedRequest(perpRoutes.orders.batchCreate(), {
|
|
299
354
|
method: "POST",
|
|
300
355
|
body: JSON.stringify(requestBody),
|
|
301
356
|
});
|
|
@@ -335,7 +390,7 @@ export class TradingAPIImpl extends BaseAPI {
|
|
|
335
390
|
use_master_balance: order.useMasterBalance,
|
|
336
391
|
})),
|
|
337
392
|
};
|
|
338
|
-
return this.makeAuthenticatedRequest(
|
|
393
|
+
return this.makeAuthenticatedRequest(perpRoutes.orders.batchReplace(), {
|
|
339
394
|
method: "POST",
|
|
340
395
|
body: JSON.stringify(requestBody),
|
|
341
396
|
});
|
|
@@ -348,7 +403,7 @@ export class TradingAPIImpl extends BaseAPI {
|
|
|
348
403
|
*
|
|
349
404
|
* @param params - Query parameters for filtering orders
|
|
350
405
|
* @param params.status - Filter by order status (e.g., "SUBMITTED", "FILLED") (optional)
|
|
351
|
-
* @param params.
|
|
406
|
+
* @param params.trading_pair_id - Filter by trading pair UUID (optional)
|
|
352
407
|
* @param params.page - Page number for pagination (defaults to 1, must be > 0)
|
|
353
408
|
* @param params.page_size - Number of orders per page (defaults to 10, max 100, must be > 0)
|
|
354
409
|
* @returns Promise resolving to GetPaginatedOrdersResponse with orders and pagination info
|
|
@@ -359,7 +414,7 @@ export class TradingAPIImpl extends BaseAPI {
|
|
|
359
414
|
* // Get submitted orders for a specific trading pair with custom pagination
|
|
360
415
|
* const orders = await tradingAPI.getPaginatedOrders({
|
|
361
416
|
* status: "SUBMITTED",
|
|
362
|
-
*
|
|
417
|
+
* trading_pair_id: "456e7890-e12b-12d3-a456-426614174000",
|
|
363
418
|
* page: 1,
|
|
364
419
|
* page_size: 20
|
|
365
420
|
* });
|
|
@@ -375,7 +430,7 @@ export class TradingAPIImpl extends BaseAPI {
|
|
|
375
430
|
validate(GetPaginatedOrdersSchema, params);
|
|
376
431
|
}
|
|
377
432
|
// Set pagination defaults with destructuring and validation
|
|
378
|
-
const { page = 1, page_size = 10, status,
|
|
433
|
+
const { page = 1, page_size = 10, status, trading_pair_id, trading_mode, margin_account_id } = params || {};
|
|
379
434
|
const validPage = page > 0 ? page : 1;
|
|
380
435
|
const validPageSize = page_size > 0 ? page_size : 10;
|
|
381
436
|
const pageSize = Math.min(validPageSize, 100);
|
|
@@ -386,8 +441,14 @@ export class TradingAPIImpl extends BaseAPI {
|
|
|
386
441
|
if (status) {
|
|
387
442
|
searchParams.append("status", status);
|
|
388
443
|
}
|
|
389
|
-
if (
|
|
390
|
-
searchParams.append("
|
|
444
|
+
if (trading_pair_id) {
|
|
445
|
+
searchParams.append("trading_pair_id", trading_pair_id);
|
|
446
|
+
}
|
|
447
|
+
if (trading_mode) {
|
|
448
|
+
searchParams.append("trading_mode", trading_mode);
|
|
449
|
+
}
|
|
450
|
+
if (margin_account_id) {
|
|
451
|
+
searchParams.append("margin_account_id", margin_account_id);
|
|
391
452
|
}
|
|
392
453
|
const endpoint = `/api/v1/orders?${searchParams.toString()}`;
|
|
393
454
|
return await this.makeAuthenticatedRequest(endpoint, {
|
|
@@ -413,7 +474,7 @@ export class TradingAPIImpl extends BaseAPI {
|
|
|
413
474
|
* ```
|
|
414
475
|
*/
|
|
415
476
|
async getOrder(orderId) {
|
|
416
|
-
return await this.makeAuthenticatedRequest(
|
|
477
|
+
return await this.makeAuthenticatedRequest(perpRoutes.orders.get(orderId), {
|
|
417
478
|
method: "GET",
|
|
418
479
|
});
|
|
419
480
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Interval, OHLCVEvent, OrderbookEvent, OrderbookQuotationMode, OrderEvent, TradeEvent, TradingMode, UserBalanceEvent, UserMovementEvent, WebSocketStatus } from "@0xmonaco/types";
|
|
1
|
+
import type { ConditionalOrderEvent, Interval, OHLCVEvent, OrderbookEvent, OrderbookQuotationMode, OrderEvent, TradeEvent, TradingMode, UserBalanceEvent, UserMovementEvent, WebSocketStatus } from "@0xmonaco/types";
|
|
2
2
|
export type StatusHandler = (status: WebSocketStatus) => void;
|
|
3
3
|
export type MessageHandler<T> = (data: T) => void;
|
|
4
4
|
export interface MonacoWebSocketOptions {
|
|
@@ -36,4 +36,6 @@ export interface MonacoWebSocket {
|
|
|
36
36
|
userOrders: (handler: MessageHandler<OrderEvent>) => () => void;
|
|
37
37
|
/** Subscribe to user balance events (requires authentication) */
|
|
38
38
|
balances: (handler: MessageHandler<UserBalanceEvent>) => () => void;
|
|
39
|
+
/** Subscribe to conditional TP/SL lifecycle events (requires authentication) */
|
|
40
|
+
conditionalOrders: (handler: MessageHandler<ConditionalOrderEvent>, tradingPairId?: string) => () => void;
|
|
39
41
|
}
|
|
@@ -4,6 +4,100 @@ import { keysToCamelCase } from "./utils";
|
|
|
4
4
|
const CONNECTION_TIMEOUT = 10000;
|
|
5
5
|
const HEARTBEAT_INTERVAL = 15000;
|
|
6
6
|
const MAX_RECONNECT_DELAY = 30000;
|
|
7
|
+
const CONDITIONAL_ORDER_REASONS = ["created", "cancelled", "triggered", "failed", "oco_cancelled"];
|
|
8
|
+
const CONDITIONAL_ORDER_CONDITION_TYPES = ["STOP_LOSS", "TAKE_PROFIT"];
|
|
9
|
+
const CONDITIONAL_ORDER_TRIGGER_SOURCES = ["MARK_PRICE"];
|
|
10
|
+
const CONDITIONAL_ORDER_STATES = ["ACTIVE", "TRIGGERING", "TRIGGERED", "CANCELLED", "EXPIRED", "FAILED"];
|
|
11
|
+
function isRecord(value) {
|
|
12
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
13
|
+
}
|
|
14
|
+
function readString(source, field) {
|
|
15
|
+
const value = source[field];
|
|
16
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
17
|
+
throw new Error(`Invalid conditional order event: ${field} must be a non-empty string`);
|
|
18
|
+
}
|
|
19
|
+
return value;
|
|
20
|
+
}
|
|
21
|
+
function readOptionalString(source, field) {
|
|
22
|
+
const value = source[field];
|
|
23
|
+
if (value === undefined || value === null)
|
|
24
|
+
return undefined;
|
|
25
|
+
if (typeof value !== "string") {
|
|
26
|
+
throw new Error(`Invalid conditional order event: ${field} must be a string`);
|
|
27
|
+
}
|
|
28
|
+
return value;
|
|
29
|
+
}
|
|
30
|
+
function readBoolean(source, field) {
|
|
31
|
+
const value = source[field];
|
|
32
|
+
if (typeof value !== "boolean") {
|
|
33
|
+
throw new Error(`Invalid conditional order event: ${field} must be a boolean`);
|
|
34
|
+
}
|
|
35
|
+
return value;
|
|
36
|
+
}
|
|
37
|
+
function readOptionalNumber(source, field) {
|
|
38
|
+
const value = source[field];
|
|
39
|
+
if (value === undefined || value === null)
|
|
40
|
+
return undefined;
|
|
41
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
42
|
+
throw new Error(`Invalid conditional order event: ${field} must be a finite number`);
|
|
43
|
+
}
|
|
44
|
+
return value;
|
|
45
|
+
}
|
|
46
|
+
function readEnum(source, field, allowed) {
|
|
47
|
+
const value = readString(source, field);
|
|
48
|
+
if (!allowed.includes(value)) {
|
|
49
|
+
throw new Error(`Invalid conditional order event: ${field} must be one of ${allowed.join(", ")}`);
|
|
50
|
+
}
|
|
51
|
+
return value;
|
|
52
|
+
}
|
|
53
|
+
function readOptionalEnum(source, field, allowed) {
|
|
54
|
+
const value = source[field];
|
|
55
|
+
if (value === undefined || value === null)
|
|
56
|
+
return undefined;
|
|
57
|
+
if (typeof value !== "string" || !allowed.includes(value)) {
|
|
58
|
+
throw new Error(`Invalid conditional order event: ${field} must be one of ${allowed.join(", ")}`);
|
|
59
|
+
}
|
|
60
|
+
return value;
|
|
61
|
+
}
|
|
62
|
+
function parseConditionalOrderEvent(rawData) {
|
|
63
|
+
if (!isRecord(rawData)) {
|
|
64
|
+
throw new Error("Invalid conditional order event: payload must be an object");
|
|
65
|
+
}
|
|
66
|
+
if (!isRecord(rawData.data)) {
|
|
67
|
+
throw new Error("Invalid conditional order event: data must be an object");
|
|
68
|
+
}
|
|
69
|
+
const data = keysToCamelCase(rawData.data);
|
|
70
|
+
return {
|
|
71
|
+
eventType: readEnum(rawData, "event_type", ["conditional_order_update"]),
|
|
72
|
+
userId: readString(rawData, "user_id"),
|
|
73
|
+
data: {
|
|
74
|
+
conditionalOrderId: readString(data, "conditionalOrderId"),
|
|
75
|
+
tradingPairId: readString(data, "tradingPairId"),
|
|
76
|
+
marginAccountId: readString(data, "marginAccountId"),
|
|
77
|
+
positionId: readOptionalString(data, "positionId"),
|
|
78
|
+
linkedGroupId: readOptionalString(data, "linkedGroupId"),
|
|
79
|
+
conditionType: readEnum(data, "conditionType", CONDITIONAL_ORDER_CONDITION_TYPES),
|
|
80
|
+
triggerSource: readEnum(data, "triggerSource", CONDITIONAL_ORDER_TRIGGER_SOURCES),
|
|
81
|
+
triggerPrice: readString(data, "triggerPrice"),
|
|
82
|
+
side: readEnum(data, "side", ["BUY", "SELL"]),
|
|
83
|
+
positionSide: readEnum(data, "positionSide", ["LONG", "SHORT", "NONE"]),
|
|
84
|
+
orderType: readEnum(data, "orderType", ["LIMIT", "MARKET"]),
|
|
85
|
+
limitPrice: readOptionalString(data, "limitPrice"),
|
|
86
|
+
quantity: readOptionalString(data, "quantity"),
|
|
87
|
+
slippageToleranceBps: readOptionalNumber(data, "slippageToleranceBps"),
|
|
88
|
+
reduceOnly: readBoolean(data, "reduceOnly"),
|
|
89
|
+
timeInForce: readOptionalEnum(data, "timeInForce", ["GTC", "IOC"]),
|
|
90
|
+
state: readEnum(data, "state", CONDITIONAL_ORDER_STATES),
|
|
91
|
+
triggeredOrderId: readOptionalString(data, "triggeredOrderId"),
|
|
92
|
+
triggeredAt: readOptionalString(data, "triggeredAt"),
|
|
93
|
+
cancelledAt: readOptionalString(data, "cancelledAt"),
|
|
94
|
+
expiresAt: readOptionalString(data, "expiresAt"),
|
|
95
|
+
failureReason: readOptionalString(data, "failureReason"),
|
|
96
|
+
reason: readEnum(data, "reason", CONDITIONAL_ORDER_REASONS),
|
|
97
|
+
updatedAt: readString(data, "updatedAt"),
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
}
|
|
7
101
|
/**
|
|
8
102
|
* Create a Monaco WebSocket client
|
|
9
103
|
*/
|
|
@@ -62,7 +156,11 @@ export function createMonacoWebSocket(baseUrl, options = {}) {
|
|
|
62
156
|
}
|
|
63
157
|
reconnectAttempts++;
|
|
64
158
|
const delay = Math.min(1000 * 2 ** reconnectAttempts, MAX_RECONNECT_DELAY);
|
|
65
|
-
reconnectTimer = setTimeout(() =>
|
|
159
|
+
reconnectTimer = setTimeout(() => {
|
|
160
|
+
connect().catch((err) => {
|
|
161
|
+
console.warn("WebSocket: Failed to reconnect:", err);
|
|
162
|
+
});
|
|
163
|
+
}, delay);
|
|
66
164
|
};
|
|
67
165
|
const send = (data) => {
|
|
68
166
|
if (ws?.readyState === WebSocket.OPEN) {
|
|
@@ -84,7 +182,6 @@ export function createMonacoWebSocket(baseUrl, options = {}) {
|
|
|
84
182
|
for (const handler of channelHandlers) {
|
|
85
183
|
handler(msg.data);
|
|
86
184
|
}
|
|
87
|
-
return;
|
|
88
185
|
}
|
|
89
186
|
}
|
|
90
187
|
};
|
|
@@ -96,22 +193,33 @@ export function createMonacoWebSocket(baseUrl, options = {}) {
|
|
|
96
193
|
return;
|
|
97
194
|
}
|
|
98
195
|
try {
|
|
99
|
-
|
|
196
|
+
const socket = new WebSocket(getUrl());
|
|
197
|
+
ws = socket;
|
|
100
198
|
const timeout = setTimeout(() => {
|
|
101
|
-
if (ws
|
|
102
|
-
|
|
199
|
+
if (ws !== socket) {
|
|
200
|
+
resolve();
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
if (socket.readyState === WebSocket.CONNECTING) {
|
|
204
|
+
socket.close(1000, "Connection timeout");
|
|
103
205
|
reject(new Error("WebSocket connection timeout"));
|
|
104
206
|
}
|
|
105
207
|
}, CONNECTION_TIMEOUT);
|
|
106
|
-
|
|
208
|
+
socket.onopen = () => {
|
|
107
209
|
clearTimeout(timeout);
|
|
210
|
+
if (ws !== socket) {
|
|
211
|
+
resolve();
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
108
214
|
reconnectAttempts = 0;
|
|
109
215
|
startHeartbeat();
|
|
110
216
|
resubscribeAll();
|
|
111
217
|
options.onStatusChange?.("connected");
|
|
112
218
|
resolve();
|
|
113
219
|
};
|
|
114
|
-
|
|
220
|
+
socket.onmessage = (event) => {
|
|
221
|
+
if (ws !== socket)
|
|
222
|
+
return;
|
|
115
223
|
try {
|
|
116
224
|
const msg = JSON.parse(event.data);
|
|
117
225
|
// Handle pong silently
|
|
@@ -123,8 +231,13 @@ export function createMonacoWebSocket(baseUrl, options = {}) {
|
|
|
123
231
|
console.warn("WebSocket: Failed to parse message", err);
|
|
124
232
|
}
|
|
125
233
|
};
|
|
126
|
-
|
|
234
|
+
socket.onclose = (event) => {
|
|
127
235
|
clearTimeout(timeout);
|
|
236
|
+
if (ws !== socket) {
|
|
237
|
+
resolve();
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
ws = null;
|
|
128
241
|
stopHeartbeat();
|
|
129
242
|
options.onStatusChange?.("disconnected");
|
|
130
243
|
// Reconnect on abnormal close
|
|
@@ -132,7 +245,7 @@ export function createMonacoWebSocket(baseUrl, options = {}) {
|
|
|
132
245
|
scheduleReconnect();
|
|
133
246
|
}
|
|
134
247
|
};
|
|
135
|
-
|
|
248
|
+
socket.onerror = () => clearTimeout(timeout);
|
|
136
249
|
}
|
|
137
250
|
catch (err) {
|
|
138
251
|
options.onStatusChange?.("disconnected");
|
|
@@ -207,7 +320,7 @@ export function createMonacoWebSocket(baseUrl, options = {}) {
|
|
|
207
320
|
const data = rawData;
|
|
208
321
|
const orderbookData = data.data;
|
|
209
322
|
const event = {
|
|
210
|
-
tradingPairId: data.
|
|
323
|
+
tradingPairId: data.symbol,
|
|
211
324
|
tradingMode: data.trading_mode,
|
|
212
325
|
bids: (orderbookData?.bids || []).map((level) => ({
|
|
213
326
|
price: level.price,
|
|
@@ -251,7 +364,7 @@ export function createMonacoWebSocket(baseUrl, options = {}) {
|
|
|
251
364
|
const data = rawData;
|
|
252
365
|
const ohlcvData = data.data;
|
|
253
366
|
const event = {
|
|
254
|
-
tradingPairId: data.
|
|
367
|
+
tradingPairId: data.symbol,
|
|
255
368
|
tradingMode: data.trading_mode,
|
|
256
369
|
interval: data.interval,
|
|
257
370
|
candlestick: {
|
|
@@ -262,7 +375,7 @@ export function createMonacoWebSocket(baseUrl, options = {}) {
|
|
|
262
375
|
l: ohlcvData.low || "0",
|
|
263
376
|
c: ohlcvData.close || "0",
|
|
264
377
|
v: ohlcvData.volume || "0",
|
|
265
|
-
s: data.
|
|
378
|
+
s: data.symbol,
|
|
266
379
|
i: data.interval,
|
|
267
380
|
n: ohlcvData.trades_count || 0,
|
|
268
381
|
},
|
|
@@ -282,7 +395,7 @@ export function createMonacoWebSocket(baseUrl, options = {}) {
|
|
|
282
395
|
const tradeData = data.data;
|
|
283
396
|
const event = {
|
|
284
397
|
eventType: "trade",
|
|
285
|
-
tradingPairId: data.
|
|
398
|
+
tradingPairId: data.trading_pair_id,
|
|
286
399
|
tradingMode: data.trading_mode.toUpperCase(),
|
|
287
400
|
data: {
|
|
288
401
|
tradeId: tradeData.trade_id,
|
|
@@ -393,18 +506,40 @@ export function createMonacoWebSocket(baseUrl, options = {}) {
|
|
|
393
506
|
}
|
|
394
507
|
});
|
|
395
508
|
};
|
|
509
|
+
const subscribeConditionalOrders = (handler, tradingPairId) => {
|
|
510
|
+
if (!handler) {
|
|
511
|
+
throw new Error("conditionalOrders subscription requires a handler");
|
|
512
|
+
}
|
|
513
|
+
if (tradingPairId !== undefined && tradingPairId.length === 0) {
|
|
514
|
+
throw new Error("conditionalOrders tradingPairId cannot be empty");
|
|
515
|
+
}
|
|
516
|
+
const channel = tradingPairId ? `conditional_orders:${tradingPairId}` : "conditional_orders";
|
|
517
|
+
return subscribe(channel, (rawData) => {
|
|
518
|
+
try {
|
|
519
|
+
handler(parseConditionalOrderEvent(rawData));
|
|
520
|
+
}
|
|
521
|
+
catch (err) {
|
|
522
|
+
console.error("WebSocket: Error processing conditional order event", err);
|
|
523
|
+
}
|
|
524
|
+
});
|
|
525
|
+
};
|
|
396
526
|
return {
|
|
397
527
|
connect,
|
|
398
528
|
disconnect,
|
|
399
529
|
isConnected: () => ws?.readyState === WebSocket.OPEN,
|
|
400
530
|
getStatus,
|
|
401
531
|
setToken: (newToken) => {
|
|
402
|
-
token = newToken;
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
532
|
+
token = newToken || undefined;
|
|
533
|
+
stopReconnect();
|
|
534
|
+
const currentSocket = ws;
|
|
535
|
+
if (currentSocket?.readyState === WebSocket.OPEN ||
|
|
536
|
+
currentSocket?.readyState === WebSocket.CONNECTING ||
|
|
537
|
+
currentSocket?.readyState === WebSocket.CLOSING) {
|
|
538
|
+
currentSocket.close(1000, newToken ? "Token updated, reconnecting." : "Token cleared.");
|
|
406
539
|
ws = null;
|
|
407
540
|
}
|
|
541
|
+
if (!newToken)
|
|
542
|
+
return;
|
|
408
543
|
connect().catch((err) => {
|
|
409
544
|
console.warn("WebSocket: Failed to reconnect after token update:", err);
|
|
410
545
|
});
|
|
@@ -416,5 +551,6 @@ export function createMonacoWebSocket(baseUrl, options = {}) {
|
|
|
416
551
|
movements: subscribeMovements,
|
|
417
552
|
userOrders: subscribeUserOrders,
|
|
418
553
|
balances: subscribeBalances,
|
|
554
|
+
conditionalOrders: subscribeConditionalOrders,
|
|
419
555
|
};
|
|
420
556
|
}
|
package/dist/sdk.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ApplicationsAPI, AuthAPI, AuthState, FeesAPI, MarketAPI, MonacoSDK, Network, ProfileAPI, SDKConfig, TradingAPI, VaultAPI } from "@0xmonaco/types";
|
|
1
|
+
import type { ApplicationsAPI, AuthAPI, AuthState, FeesAPI, MarginAccountsAPI, MarketAPI, MonacoSDK, Network, PositionsAPI, ProfileAPI, SDKConfig, TradingAPI, VaultAPI } from "@0xmonaco/types";
|
|
2
2
|
import { type PublicClient, type TransactionReceipt, type WalletClient } from "viem";
|
|
3
3
|
import { type MonacoWebSocket, OrderbookAPIImpl, TradesAPIImpl } from "./api";
|
|
4
4
|
export declare class MonacoSDKImpl implements MonacoSDK {
|
|
@@ -8,6 +8,8 @@ export declare class MonacoSDKImpl implements MonacoSDK {
|
|
|
8
8
|
vault: VaultAPI;
|
|
9
9
|
trading: TradingAPI;
|
|
10
10
|
market: MarketAPI;
|
|
11
|
+
marginAccounts: MarginAccountsAPI;
|
|
12
|
+
positions: PositionsAPI;
|
|
11
13
|
profile: ProfileAPI;
|
|
12
14
|
orderbook: OrderbookAPIImpl;
|
|
13
15
|
trades: TradesAPIImpl;
|
|
@@ -31,8 +33,8 @@ export declare class MonacoSDKImpl implements MonacoSDK {
|
|
|
31
33
|
* - `expiresAt`: When the access token expires
|
|
32
34
|
* - `user`: User information
|
|
33
35
|
*
|
|
34
|
-
* Note:
|
|
35
|
-
*
|
|
36
|
+
* Note: Use `sdk.logout()` to revoke the token and clean up, or call
|
|
37
|
+
* `sdk.auth.revokeToken()` directly to just revoke.
|
|
36
38
|
*
|
|
37
39
|
* @param clientId - The client ID for authentication
|
|
38
40
|
* @param options - Optional configuration
|
|
@@ -50,7 +52,7 @@ export declare class MonacoSDKImpl implements MonacoSDK {
|
|
|
50
52
|
* await sdk.ws.connect();
|
|
51
53
|
*
|
|
52
54
|
* // Later, to revoke:
|
|
53
|
-
* await sdk.auth.revokeToken(
|
|
55
|
+
* await sdk.auth.revokeToken(); // ✅
|
|
54
56
|
* // Or revoke and disconnect WebSocket:
|
|
55
57
|
* await sdk.logout(); // ✅ Calls revokeToken internally and disconnects WebSocket
|
|
56
58
|
* ```
|
|
@@ -76,7 +78,7 @@ export declare class MonacoSDKImpl implements MonacoSDK {
|
|
|
76
78
|
*
|
|
77
79
|
* This method revokes the refresh token (if available), disconnects all authenticated
|
|
78
80
|
* WebSocket channels, and clears the local auth state.
|
|
79
|
-
* It internally calls `auth.revokeToken(
|
|
81
|
+
* It internally calls `auth.revokeToken()` to invalidate the token on the server.
|
|
80
82
|
*
|
|
81
83
|
* @example
|
|
82
84
|
* ```typescript
|
package/dist/sdk.js
CHANGED
|
@@ -4,7 +4,9 @@ import { sei, seiTestnet } from "viem/chains";
|
|
|
4
4
|
import { ApplicationsAPIImpl, createMonacoWebSocket, OrderbookAPIImpl, TradesAPIImpl } from "./api";
|
|
5
5
|
import { AuthAPIImpl } from "./api/auth";
|
|
6
6
|
import { FeesAPIImpl } from "./api/fees";
|
|
7
|
+
import { MarginAccountsAPIImpl } from "./api/margin-accounts";
|
|
7
8
|
import { MarketAPIImpl } from "./api/market";
|
|
9
|
+
import { PositionsAPIImpl } from "./api/positions";
|
|
8
10
|
import { ProfileAPIImpl } from "./api/profile";
|
|
9
11
|
import { TradingAPIImpl } from "./api/trading";
|
|
10
12
|
import { VaultAPIImpl } from "./api/vault";
|
|
@@ -17,6 +19,8 @@ export class MonacoSDKImpl {
|
|
|
17
19
|
vault;
|
|
18
20
|
trading;
|
|
19
21
|
market;
|
|
22
|
+
marginAccounts;
|
|
23
|
+
positions;
|
|
20
24
|
profile;
|
|
21
25
|
orderbook;
|
|
22
26
|
trades;
|
|
@@ -36,7 +40,11 @@ export class MonacoSDKImpl {
|
|
|
36
40
|
this.vault.setAccessToken(accessToken);
|
|
37
41
|
this.trading.setAccessToken(accessToken);
|
|
38
42
|
this.market.setAccessToken(accessToken);
|
|
43
|
+
this.marginAccounts.setAccessToken(accessToken);
|
|
44
|
+
this.positions.setAccessToken(accessToken);
|
|
39
45
|
this.profile.setAccessToken(accessToken);
|
|
46
|
+
this.orderbook.setAccessToken(accessToken);
|
|
47
|
+
this.trades.setAccessToken(accessToken);
|
|
40
48
|
this.ws.setToken(accessToken);
|
|
41
49
|
}
|
|
42
50
|
constructor(cfg) {
|
|
@@ -79,6 +87,8 @@ export class MonacoSDKImpl {
|
|
|
79
87
|
// Instantiate APIs (wallet-dependent APIs will be initialized lazily or error if wallet not set)
|
|
80
88
|
this.applications = new ApplicationsAPIImpl(apiUrl);
|
|
81
89
|
this.market = new MarketAPIImpl(apiUrl);
|
|
90
|
+
this.marginAccounts = new MarginAccountsAPIImpl(apiUrl);
|
|
91
|
+
this.positions = new PositionsAPIImpl(apiUrl);
|
|
82
92
|
this.auth = new AuthAPIImpl(this.walletClient, this.chain, apiUrl);
|
|
83
93
|
this.fees = new FeesAPIImpl(apiUrl);
|
|
84
94
|
this.profile = new ProfileAPIImpl(apiUrl);
|
|
@@ -99,8 +109,8 @@ export class MonacoSDKImpl {
|
|
|
99
109
|
* - `expiresAt`: When the access token expires
|
|
100
110
|
* - `user`: User information
|
|
101
111
|
*
|
|
102
|
-
* Note:
|
|
103
|
-
*
|
|
112
|
+
* Note: Use `sdk.logout()` to revoke the token and clean up, or call
|
|
113
|
+
* `sdk.auth.revokeToken()` directly to just revoke.
|
|
104
114
|
*
|
|
105
115
|
* @param clientId - The client ID for authentication
|
|
106
116
|
* @param options - Optional configuration
|
|
@@ -118,7 +128,7 @@ export class MonacoSDKImpl {
|
|
|
118
128
|
* await sdk.ws.connect();
|
|
119
129
|
*
|
|
120
130
|
* // Later, to revoke:
|
|
121
|
-
* await sdk.auth.revokeToken(
|
|
131
|
+
* await sdk.auth.revokeToken(); // ✅
|
|
122
132
|
* // Or revoke and disconnect WebSocket:
|
|
123
133
|
* await sdk.logout(); // ✅ Calls revokeToken internally and disconnects WebSocket
|
|
124
134
|
* ```
|
|
@@ -161,7 +171,7 @@ export class MonacoSDKImpl {
|
|
|
161
171
|
*
|
|
162
172
|
* This method revokes the refresh token (if available), disconnects all authenticated
|
|
163
173
|
* WebSocket channels, and clears the local auth state.
|
|
164
|
-
* It internally calls `auth.revokeToken(
|
|
174
|
+
* It internally calls `auth.revokeToken()` to invalidate the token on the server.
|
|
165
175
|
*
|
|
166
176
|
* @example
|
|
167
177
|
* ```typescript
|
|
@@ -172,18 +182,16 @@ export class MonacoSDKImpl {
|
|
|
172
182
|
async logout() {
|
|
173
183
|
if (this.authState?.refreshToken) {
|
|
174
184
|
try {
|
|
175
|
-
await this.auth.revokeToken(
|
|
185
|
+
await this.auth.revokeToken();
|
|
176
186
|
}
|
|
177
187
|
catch (error) {
|
|
178
188
|
// Log but don't throw - we want to clear the local state regardless
|
|
179
189
|
console.warn("Failed to revoke token on logout:", error);
|
|
180
190
|
}
|
|
181
191
|
}
|
|
182
|
-
// Disconnect WebSocket if connected
|
|
183
|
-
if (this.ws.isConnected()) {
|
|
184
|
-
this.ws.disconnect();
|
|
185
|
-
}
|
|
186
192
|
this.authState = undefined;
|
|
193
|
+
this.propagateAccessToken("");
|
|
194
|
+
this.ws.disconnect();
|
|
187
195
|
}
|
|
188
196
|
/**
|
|
189
197
|
* Refresh the access token
|