@0xmonaco/core 0.0.0-develop-20260415185155 → 0.0.0-develop-20260420223958

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.
@@ -6,8 +6,11 @@
6
6
  export * from "./applications/index";
7
7
  export * from "./base";
8
8
  export * from "./fees";
9
+ export * from "./margin-accounts";
9
10
  export * from "./market";
10
11
  export * from "./orderbook";
12
+ export * from "./perp";
13
+ export * from "./positions";
11
14
  export * from "./profile";
12
15
  export * from "./trades";
13
16
  export * from "./trading";
package/dist/api/index.js CHANGED
@@ -6,8 +6,11 @@
6
6
  export * from "./applications/index";
7
7
  export * from "./base";
8
8
  export * from "./fees";
9
+ export * from "./margin-accounts";
9
10
  export * from "./market";
10
11
  export * from "./orderbook";
12
+ export * from "./perp";
13
+ export * from "./positions";
11
14
  export * from "./profile";
12
15
  export * from "./trades";
13
16
  export * from "./trading";
@@ -0,0 +1,12 @@
1
+ import type { CreateMarginAccountRequest, CreateMarginAccountResponse, GetAvailableCollateralParams, GetAvailableCollateralResponse, GetMarginAccountMovementsParams, GetMarginAccountMovementsResponse, ListMarginAccountsParams, ListMarginAccountsResponse, MarginAccountSummary, MarginAccountsAPI, SimulateOrderRiskRequest, SimulateOrderRiskResponse, TransferCollateralRequest, TransferCollateralResponse } from "@0xmonaco/types";
2
+ import { BaseAPI } from "../base";
3
+ export declare class MarginAccountsAPIImpl extends BaseAPI implements MarginAccountsAPI {
4
+ listMarginAccounts(params?: ListMarginAccountsParams): Promise<ListMarginAccountsResponse>;
5
+ createMarginAccount(request?: CreateMarginAccountRequest): Promise<CreateMarginAccountResponse>;
6
+ getMarginAccountSummary(marginAccountId: string): Promise<MarginAccountSummary>;
7
+ getAvailableCollateral(params?: GetAvailableCollateralParams): Promise<GetAvailableCollateralResponse>;
8
+ transferCollateralToMarginAccount(marginAccountId: string, request: TransferCollateralRequest): Promise<TransferCollateralResponse>;
9
+ transferCollateralFromMarginAccount(marginAccountId: string, request: TransferCollateralRequest): Promise<TransferCollateralResponse>;
10
+ getMarginAccountMovements(marginAccountId: string, params?: GetMarginAccountMovementsParams): Promise<GetMarginAccountMovementsResponse>;
11
+ simulateOrderRisk(marginAccountId: string, request: SimulateOrderRiskRequest): Promise<SimulateOrderRiskResponse>;
12
+ }
@@ -0,0 +1,69 @@
1
+ import { CreateMarginAccountSchema, GetAvailableCollateralSchema, GetMarginAccountMovementsSchema, GetMarginAccountSummarySchema, ListMarginAccountsSchema, SimulateOrderRiskSchema, TransferCollateralSchema, validate, } from "@0xmonaco/types";
2
+ import { BaseAPI } from "../base";
3
+ import { perpRoutes } from "../perp";
4
+ export class MarginAccountsAPIImpl extends BaseAPI {
5
+ async listMarginAccounts(params) {
6
+ if (params) {
7
+ validate(ListMarginAccountsSchema, params);
8
+ }
9
+ return await this.makeAuthenticatedRequest(perpRoutes.marginAccounts.list(params));
10
+ }
11
+ async createMarginAccount(request) {
12
+ validate(CreateMarginAccountSchema, request);
13
+ return await this.makeAuthenticatedRequest(perpRoutes.marginAccounts.create(), {
14
+ method: "POST",
15
+ body: JSON.stringify({
16
+ label: request?.label,
17
+ collateral_asset: request?.collateralAsset,
18
+ }),
19
+ });
20
+ }
21
+ async getMarginAccountSummary(marginAccountId) {
22
+ validate(GetMarginAccountSummarySchema, { marginAccountId });
23
+ return await this.makeAuthenticatedRequest(perpRoutes.marginAccounts.summary(marginAccountId));
24
+ }
25
+ async getAvailableCollateral(params) {
26
+ validate(GetAvailableCollateralSchema, params);
27
+ return await this.makeAuthenticatedRequest(perpRoutes.marginAccounts.availableCollateral(params));
28
+ }
29
+ async transferCollateralToMarginAccount(marginAccountId, request) {
30
+ validate(TransferCollateralSchema, { marginAccountId, request });
31
+ return await this.makeAuthenticatedRequest(perpRoutes.marginAccounts.transferIn(marginAccountId), {
32
+ method: "POST",
33
+ body: JSON.stringify({
34
+ asset: request.asset,
35
+ amount: request.amount,
36
+ }),
37
+ });
38
+ }
39
+ async transferCollateralFromMarginAccount(marginAccountId, request) {
40
+ validate(TransferCollateralSchema, { marginAccountId, request });
41
+ return await this.makeAuthenticatedRequest(perpRoutes.marginAccounts.transferOut(marginAccountId), {
42
+ method: "POST",
43
+ body: JSON.stringify({
44
+ asset: request.asset,
45
+ amount: request.amount,
46
+ }),
47
+ });
48
+ }
49
+ async getMarginAccountMovements(marginAccountId, params) {
50
+ validate(GetMarginAccountMovementsSchema, { marginAccountId, ...params });
51
+ return await this.makeAuthenticatedRequest(perpRoutes.marginAccounts.movements(marginAccountId, params));
52
+ }
53
+ async simulateOrderRisk(marginAccountId, request) {
54
+ validate(SimulateOrderRiskSchema, { marginAccountId, request });
55
+ return await this.makeAuthenticatedRequest(perpRoutes.marginAccounts.simulateOrderRisk(marginAccountId), {
56
+ method: "POST",
57
+ body: JSON.stringify({
58
+ trading_pair_id: request.tradingPairId,
59
+ side: request.side,
60
+ position_side: request.positionSide,
61
+ order_type: request.orderType,
62
+ price: request.price,
63
+ quantity: request.quantity,
64
+ leverage: request.leverage,
65
+ reduce_only: request.reduceOnly,
66
+ }),
67
+ });
68
+ }
69
+ }
@@ -0,0 +1 @@
1
+ export { MarginAccountsAPIImpl } from "./api";
@@ -0,0 +1 @@
1
+ export { MarginAccountsAPIImpl } from "./api";
@@ -1,4 +1,4 @@
1
- import type { Candlestick, GetCandlesticksParams, GetTradingPairsParams, GetTradingPairsResponse, Interval, MarketAPI, MarketMetadata, TradingPair } from "@0xmonaco/types";
1
+ import type { Candlestick, FundingState, GetCandlesticksParams, GetTradingPairsParams, GetTradingPairsResponse, IndexPrice, Interval, ListFundingHistoryParams, ListFundingHistoryResponse, MarketAPI, MarketMetadata, MarkPrice, OpenInterest, PerpMarketConfig, PerpMarketSummary, TradingPair } from "@0xmonaco/types";
2
2
  import { BaseAPI } from "../base";
3
3
  /**
4
4
  * Market API Implementation
@@ -10,4 +10,11 @@ export declare class MarketAPIImpl extends BaseAPI implements MarketAPI {
10
10
  getTradingPairBySymbol(symbol: string): Promise<TradingPair | undefined>;
11
11
  getCandlesticks(tradingPairId: string, interval: Interval, params?: GetCandlesticksParams): Promise<Candlestick[]>;
12
12
  getMarketMetadata(tradingPairId: string): Promise<MarketMetadata>;
13
+ getPerpMarketConfig(tradingPairId: string): Promise<PerpMarketConfig>;
14
+ getPerpMarketSummary(tradingPairId: string): Promise<PerpMarketSummary>;
15
+ getMarkPrice(tradingPairId: string): Promise<MarkPrice>;
16
+ getIndexPrice(tradingPairId: string): Promise<IndexPrice>;
17
+ getFundingState(tradingPairId: string): Promise<FundingState>;
18
+ listFundingHistory(tradingPairId: string, params?: ListFundingHistoryParams): Promise<ListFundingHistoryResponse>;
19
+ getOpenInterest(tradingPairId: string): Promise<OpenInterest>;
13
20
  }
@@ -1,5 +1,6 @@
1
1
  import { GetCandlesticksByPairIdSchema, GetMarketMetadataSchema, validate } from "@0xmonaco/types";
2
2
  import { BaseAPI } from "../base";
3
+ import { perpRoutes } from "../perp";
3
4
  /**
4
5
  * Market API Implementation
5
6
  *
@@ -63,7 +64,34 @@ export class MarketAPIImpl extends BaseAPI {
63
64
  }
64
65
  async getMarketMetadata(tradingPairId) {
65
66
  validate(GetMarketMetadataSchema, { tradingPairId });
66
- const url = `/api/v1/market/pairs/${tradingPairId}/metadata`;
67
- return await this.makePublicRequest(url);
67
+ return await this.makePublicRequest(perpRoutes.market.getMarketMetadata(tradingPairId));
68
+ }
69
+ async getPerpMarketConfig(tradingPairId) {
70
+ validate(GetMarketMetadataSchema, { tradingPairId });
71
+ return await this.makePublicRequest(perpRoutes.market.getPerpMarketConfig(tradingPairId));
72
+ }
73
+ async getPerpMarketSummary(tradingPairId) {
74
+ validate(GetMarketMetadataSchema, { tradingPairId });
75
+ return await this.makePublicRequest(perpRoutes.market.getPerpMarketSummary(tradingPairId));
76
+ }
77
+ async getMarkPrice(tradingPairId) {
78
+ validate(GetMarketMetadataSchema, { tradingPairId });
79
+ return await this.makePublicRequest(perpRoutes.market.getMarkPrice(tradingPairId));
80
+ }
81
+ async getIndexPrice(tradingPairId) {
82
+ validate(GetMarketMetadataSchema, { tradingPairId });
83
+ return await this.makePublicRequest(perpRoutes.market.getIndexPrice(tradingPairId));
84
+ }
85
+ async getFundingState(tradingPairId) {
86
+ validate(GetMarketMetadataSchema, { tradingPairId });
87
+ return await this.makePublicRequest(perpRoutes.market.getFundingState(tradingPairId));
88
+ }
89
+ async listFundingHistory(tradingPairId, params) {
90
+ validate(GetMarketMetadataSchema, { tradingPairId });
91
+ return await this.makePublicRequest(perpRoutes.market.listFundingHistory(tradingPairId, params));
92
+ }
93
+ async getOpenInterest(tradingPairId) {
94
+ validate(GetMarketMetadataSchema, { tradingPairId });
95
+ return await this.makePublicRequest(perpRoutes.market.getOpenInterest(tradingPairId));
68
96
  }
69
97
  }
@@ -0,0 +1 @@
1
+ export { perpRoutes } from "./routes";
@@ -0,0 +1 @@
1
+ export { perpRoutes } from "./routes";
@@ -0,0 +1,133 @@
1
+ export declare const perpRoutes: {
2
+ readonly orders: {
3
+ readonly create: () => string;
4
+ readonly list: (params?: {
5
+ page?: number;
6
+ page_size?: number;
7
+ status?: string;
8
+ trading_pair?: string;
9
+ trading_mode?: string;
10
+ margin_account_id?: string;
11
+ }) => string;
12
+ readonly get: (orderId: string) => string;
13
+ readonly replace: (orderId: string) => string;
14
+ readonly cancel: () => string;
15
+ readonly batchCancel: () => string;
16
+ readonly batchCancelAll: () => string;
17
+ readonly batchCancelAllByPair: (tradingPairId: string) => string;
18
+ readonly batchCreate: () => string;
19
+ readonly batchReplace: () => string;
20
+ readonly createConditional: () => string;
21
+ readonly listConditional: (params?: {
22
+ margin_account_id?: string;
23
+ trading_pair_id?: string;
24
+ state?: string;
25
+ page?: number;
26
+ page_size?: number;
27
+ }) => string;
28
+ readonly cancelConditional: (conditionalOrderId: string) => string;
29
+ };
30
+ readonly market: {
31
+ readonly listTradingPairs: (params?: {
32
+ page?: number;
33
+ limit?: number;
34
+ market_type?: string;
35
+ base_token?: string;
36
+ quote_token?: string;
37
+ is_active?: boolean;
38
+ }) => string;
39
+ readonly getTradingPair: (tradingPairId: string) => string;
40
+ readonly getCandles: (tradingPairId: string, interval: string, params?: {
41
+ start_time?: number;
42
+ end_time?: number;
43
+ limit?: number;
44
+ }) => string;
45
+ readonly getMarketMetadata: (tradingPairId: string) => string;
46
+ readonly getPerpMarketConfig: (tradingPairId: string) => string;
47
+ readonly getPerpMarketSummary: (tradingPairId: string) => string;
48
+ readonly getMarkPrice: (tradingPairId: string) => string;
49
+ readonly getIndexPrice: (tradingPairId: string) => string;
50
+ readonly getFundingState: (tradingPairId: string) => string;
51
+ readonly listFundingHistory: (tradingPairId: string, params?: {
52
+ start_time?: string;
53
+ end_time?: string;
54
+ page?: number;
55
+ page_size?: number;
56
+ }) => string;
57
+ readonly getOpenInterest: (tradingPairId: string) => string;
58
+ };
59
+ readonly orderbook: {
60
+ readonly get: (tradingPairId: string, params?: {
61
+ levels?: number;
62
+ trading_mode?: string;
63
+ magnitude?: string | number;
64
+ denomination?: string;
65
+ }) => string;
66
+ };
67
+ readonly trades: {
68
+ readonly publicByPair: (tradingPairId: string, params?: {
69
+ skip?: number;
70
+ limit?: number;
71
+ }) => string;
72
+ readonly user: (params?: {
73
+ margin_account_id?: string;
74
+ trading_pair_id?: string;
75
+ page?: number;
76
+ page_size?: number;
77
+ }) => string;
78
+ };
79
+ readonly positions: {
80
+ readonly list: (params?: {
81
+ margin_account_id?: string;
82
+ trading_pair_id?: string;
83
+ status?: string;
84
+ page?: number;
85
+ page_size?: number;
86
+ }) => string;
87
+ readonly get: (positionId: string) => string;
88
+ readonly close: (positionId: string) => string;
89
+ readonly risk: (positionId: string) => string;
90
+ readonly addMargin: (positionId: string) => string;
91
+ readonly reduceMargin: (positionId: string) => string;
92
+ readonly attachTpSl: (positionId: string) => string;
93
+ readonly history: (params?: {
94
+ position_id?: string;
95
+ margin_account_id?: string;
96
+ trading_pair_id?: string;
97
+ page?: number;
98
+ page_size?: number;
99
+ }) => string;
100
+ };
101
+ readonly marginAccounts: {
102
+ readonly list: (params?: {
103
+ page?: number;
104
+ page_size?: number;
105
+ state?: string;
106
+ }) => string;
107
+ readonly create: () => string;
108
+ readonly summary: (marginAccountId: string) => string;
109
+ readonly availableCollateral: (params?: {
110
+ asset?: string;
111
+ }) => string;
112
+ readonly transferIn: (marginAccountId: string) => string;
113
+ readonly transferOut: (marginAccountId: string) => string;
114
+ readonly movements: (marginAccountId: string, params?: {
115
+ movement_type?: string;
116
+ page?: number;
117
+ page_size?: number;
118
+ }) => string;
119
+ readonly simulateOrderRisk: (marginAccountId: string) => string;
120
+ };
121
+ readonly streams: {
122
+ readonly orderbook: () => string;
123
+ readonly trades: () => string;
124
+ readonly perpMarketSummaries: () => string;
125
+ readonly markPrices: () => string;
126
+ readonly privateTrades: () => string;
127
+ readonly orders: () => string;
128
+ readonly positions: () => string;
129
+ readonly marginAccount: () => string;
130
+ readonly funding: () => string;
131
+ readonly liquidationAlerts: () => string;
132
+ };
133
+ };
@@ -0,0 +1,85 @@
1
+ const API_V1 = "/api/v1";
2
+ function encodeSegment(value) {
3
+ return encodeURIComponent(value);
4
+ }
5
+ function withQuery(path, params) {
6
+ if (!params)
7
+ return path;
8
+ const searchParams = new URLSearchParams();
9
+ for (const [key, value] of Object.entries(params)) {
10
+ if (value !== undefined) {
11
+ searchParams.set(key, String(value));
12
+ }
13
+ }
14
+ const query = searchParams.toString();
15
+ return query ? `${path}?${query}` : path;
16
+ }
17
+ export const perpRoutes = {
18
+ orders: {
19
+ create: () => `${API_V1}/orders`,
20
+ list: (params) => withQuery(`${API_V1}/orders`, params),
21
+ get: (orderId) => `${API_V1}/orders/${encodeSegment(orderId)}`,
22
+ replace: (orderId) => `${API_V1}/orders/${encodeSegment(orderId)}`,
23
+ cancel: () => `${API_V1}/orders/cancel`,
24
+ batchCancel: () => `${API_V1}/orders/batch-cancel`,
25
+ batchCancelAll: () => `${API_V1}/orders/batch-cancel-all`,
26
+ batchCancelAllByPair: (tradingPairId) => `${API_V1}/orders/batch-cancel-all/${encodeSegment(tradingPairId)}`,
27
+ batchCreate: () => `${API_V1}/orders/batch-create`,
28
+ batchReplace: () => `${API_V1}/orders/batch-replace`,
29
+ createConditional: () => `${API_V1}/orders/conditional`,
30
+ listConditional: (params) => withQuery(`${API_V1}/orders/conditional`, params),
31
+ cancelConditional: (conditionalOrderId) => `${API_V1}/orders/conditional/${encodeSegment(conditionalOrderId)}`,
32
+ },
33
+ market: {
34
+ listTradingPairs: (params) => withQuery(`${API_V1}/market/pairs`, params),
35
+ getTradingPair: (tradingPairId) => `${API_V1}/market/pairs/${encodeSegment(tradingPairId)}`,
36
+ getCandles: (tradingPairId, interval, params) => withQuery(`${API_V1}/market/pairs/charts/candlestick/${encodeSegment(tradingPairId)}/${encodeSegment(interval)}`, params),
37
+ getMarketMetadata: (tradingPairId) => `${API_V1}/market/pairs/${encodeSegment(tradingPairId)}/metadata`,
38
+ getPerpMarketConfig: (tradingPairId) => `${API_V1}/market/pairs/${encodeSegment(tradingPairId)}/perp/config`,
39
+ getPerpMarketSummary: (tradingPairId) => `${API_V1}/market/pairs/${encodeSegment(tradingPairId)}/perp/summary`,
40
+ getMarkPrice: (tradingPairId) => `${API_V1}/market/pairs/${encodeSegment(tradingPairId)}/mark-price`,
41
+ getIndexPrice: (tradingPairId) => `${API_V1}/market/pairs/${encodeSegment(tradingPairId)}/index-price`,
42
+ getFundingState: (tradingPairId) => `${API_V1}/market/pairs/${encodeSegment(tradingPairId)}/funding`,
43
+ listFundingHistory: (tradingPairId, params) => withQuery(`${API_V1}/market/pairs/${encodeSegment(tradingPairId)}/funding/history`, params),
44
+ getOpenInterest: (tradingPairId) => `${API_V1}/market/pairs/${encodeSegment(tradingPairId)}/open-interest`,
45
+ },
46
+ orderbook: {
47
+ get: (tradingPairId, params) => withQuery(`${API_V1}/orderbook/${encodeSegment(tradingPairId)}`, params),
48
+ },
49
+ trades: {
50
+ publicByPair: (tradingPairId, params) => withQuery(`${API_V1}/trades/${encodeSegment(tradingPairId)}`, params),
51
+ user: (params) => withQuery(`${API_V1}/accounts/trades`, params),
52
+ },
53
+ positions: {
54
+ list: (params) => withQuery(`${API_V1}/positions`, params),
55
+ get: (positionId) => `${API_V1}/positions/${encodeSegment(positionId)}`,
56
+ close: (positionId) => `${API_V1}/positions/${encodeSegment(positionId)}/close`,
57
+ risk: (positionId) => `${API_V1}/positions/${encodeSegment(positionId)}/risk`,
58
+ addMargin: (positionId) => `${API_V1}/positions/${encodeSegment(positionId)}/margin/add`,
59
+ reduceMargin: (positionId) => `${API_V1}/positions/${encodeSegment(positionId)}/margin/reduce`,
60
+ attachTpSl: (positionId) => `${API_V1}/positions/${encodeSegment(positionId)}/tp-sl`,
61
+ history: (params) => withQuery(`${API_V1}/positions/history`, params),
62
+ },
63
+ marginAccounts: {
64
+ list: (params) => withQuery(`${API_V1}/margin/accounts`, params),
65
+ create: () => `${API_V1}/margin/accounts`,
66
+ summary: (marginAccountId) => `${API_V1}/margin/accounts/${encodeSegment(marginAccountId)}`,
67
+ availableCollateral: (params) => withQuery(`${API_V1}/margin/collateral/available`, params),
68
+ transferIn: (marginAccountId) => `${API_V1}/margin/accounts/${encodeSegment(marginAccountId)}/collateral/transfer-in`,
69
+ transferOut: (marginAccountId) => `${API_V1}/margin/accounts/${encodeSegment(marginAccountId)}/collateral/transfer-out`,
70
+ movements: (marginAccountId, params) => withQuery(`${API_V1}/margin/accounts/${encodeSegment(marginAccountId)}/movements`, params),
71
+ simulateOrderRisk: (marginAccountId) => `${API_V1}/margin/accounts/${encodeSegment(marginAccountId)}/simulate-order-risk`,
72
+ },
73
+ streams: {
74
+ orderbook: () => `${API_V1}/streaming/orderbook`,
75
+ trades: () => `${API_V1}/streaming/trades`,
76
+ perpMarketSummaries: () => `${API_V1}/streaming/perp-market-summaries`,
77
+ markPrices: () => `${API_V1}/streaming/mark-prices`,
78
+ privateTrades: () => `${API_V1}/streaming/private-trades`,
79
+ orders: () => `${API_V1}/streaming/orders`,
80
+ positions: () => `${API_V1}/streaming/positions`,
81
+ marginAccount: () => `${API_V1}/streaming/margin-account`,
82
+ funding: () => `${API_V1}/streaming/funding`,
83
+ liquidationAlerts: () => `${API_V1}/streaming/liquidation-alerts`,
84
+ },
85
+ };
@@ -0,0 +1,12 @@
1
+ import type { AddPositionMarginRequest, AttachPositionTpSlRequest, AttachPositionTpSlResponse, ClosePositionRequest, ClosePositionResponse, GetPositionResponse, ListPositionHistoryParams, ListPositionHistoryResponse, ListPositionsParams, ListPositionsResponse, PositionMarginResponse, PositionRisk, PositionsAPI, ReducePositionMarginRequest } from "@0xmonaco/types";
2
+ import { BaseAPI } from "../base";
3
+ export declare class PositionsAPIImpl extends BaseAPI implements PositionsAPI {
4
+ listPositions(params?: ListPositionsParams): Promise<ListPositionsResponse>;
5
+ getPosition(positionId: string): Promise<GetPositionResponse>;
6
+ closePosition(positionId: string, request: ClosePositionRequest): Promise<ClosePositionResponse>;
7
+ getPositionRisk(positionId: string): Promise<PositionRisk>;
8
+ addPositionMargin(positionId: string, request: AddPositionMarginRequest): Promise<PositionMarginResponse>;
9
+ reducePositionMargin(positionId: string, request: ReducePositionMarginRequest): Promise<PositionMarginResponse>;
10
+ attachPositionTpSl(positionId: string, request: AttachPositionTpSlRequest): Promise<AttachPositionTpSlResponse>;
11
+ listPositionHistory(params?: ListPositionHistoryParams): Promise<ListPositionHistoryResponse>;
12
+ }
@@ -0,0 +1,89 @@
1
+ import { AddPositionMarginSchema, AttachPositionTpSlSchema, ClosePositionSchema, GetPositionRiskSchema, GetPositionSchema, ListPositionHistorySchema, ListPositionsSchema, ReducePositionMarginSchema, validate, } from "@0xmonaco/types";
2
+ import { BaseAPI } from "../base";
3
+ import { perpRoutes } from "../perp";
4
+ export class PositionsAPIImpl extends BaseAPI {
5
+ async listPositions(params) {
6
+ if (params) {
7
+ validate(ListPositionsSchema, params);
8
+ }
9
+ return await this.makeAuthenticatedRequest(perpRoutes.positions.list(params));
10
+ }
11
+ async getPosition(positionId) {
12
+ validate(GetPositionSchema, { positionId });
13
+ return await this.makeAuthenticatedRequest(perpRoutes.positions.get(positionId));
14
+ }
15
+ async closePosition(positionId, request) {
16
+ validate(ClosePositionSchema, { positionId, request });
17
+ return await this.makeAuthenticatedRequest(perpRoutes.positions.close(positionId), {
18
+ method: "POST",
19
+ body: JSON.stringify({
20
+ position_id: positionId,
21
+ close_type: request.closeType,
22
+ limit_price: request.limitPrice,
23
+ slippage_tolerance_bps: request.slippageToleranceBps,
24
+ quantity: request.quantity,
25
+ }),
26
+ });
27
+ }
28
+ async getPositionRisk(positionId) {
29
+ validate(GetPositionRiskSchema, { positionId });
30
+ return await this.makeAuthenticatedRequest(perpRoutes.positions.risk(positionId));
31
+ }
32
+ async addPositionMargin(positionId, request) {
33
+ validate(AddPositionMarginSchema, { positionId, request });
34
+ return await this.makeAuthenticatedRequest(perpRoutes.positions.addMargin(positionId), {
35
+ method: "POST",
36
+ body: JSON.stringify({
37
+ position_id: positionId,
38
+ amount: request.amount,
39
+ asset: request.asset,
40
+ }),
41
+ });
42
+ }
43
+ async reducePositionMargin(positionId, request) {
44
+ validate(ReducePositionMarginSchema, { positionId, request });
45
+ return await this.makeAuthenticatedRequest(perpRoutes.positions.reduceMargin(positionId), {
46
+ method: "POST",
47
+ body: JSON.stringify({
48
+ position_id: positionId,
49
+ amount: request.amount,
50
+ }),
51
+ });
52
+ }
53
+ async attachPositionTpSl(positionId, request) {
54
+ validate(AttachPositionTpSlSchema, { positionId, request });
55
+ return await this.makeAuthenticatedRequest(perpRoutes.positions.attachTpSl(positionId), {
56
+ method: "POST",
57
+ body: JSON.stringify({
58
+ take_profit: request.takeProfit
59
+ ? {
60
+ trigger_price: request.takeProfit.triggerPrice,
61
+ order_type: request.takeProfit.orderType,
62
+ limit_price: request.takeProfit.limitPrice,
63
+ quantity: request.takeProfit.quantity,
64
+ time_in_force: request.takeProfit.timeInForce,
65
+ slippage_tolerance_bps: request.takeProfit.slippageToleranceBps,
66
+ expires_at: request.takeProfit.expiresAt,
67
+ }
68
+ : undefined,
69
+ stop_loss: request.stopLoss
70
+ ? {
71
+ trigger_price: request.stopLoss.triggerPrice,
72
+ order_type: request.stopLoss.orderType,
73
+ limit_price: request.stopLoss.limitPrice,
74
+ quantity: request.stopLoss.quantity,
75
+ time_in_force: request.stopLoss.timeInForce,
76
+ slippage_tolerance_bps: request.stopLoss.slippageToleranceBps,
77
+ expires_at: request.stopLoss.expiresAt,
78
+ }
79
+ : undefined,
80
+ }),
81
+ });
82
+ }
83
+ async listPositionHistory(params) {
84
+ if (params) {
85
+ validate(ListPositionHistorySchema, params);
86
+ }
87
+ return await this.makeAuthenticatedRequest(perpRoutes.positions.history(params));
88
+ }
89
+ }
@@ -0,0 +1 @@
1
+ export { PositionsAPIImpl } from "./api";
@@ -0,0 +1 @@
1
+ export { PositionsAPIImpl } from "./api";
@@ -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
  *
@@ -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("/api/v1/orders", {
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("/api/v1/orders", {
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("/api/v1/orders/cancel", {
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("/api/v1/orders/batch-cancel", {
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 ? `/api/v1/orders/batch-cancel-all/${tradingPairId}` : "/api/v1/orders/batch-cancel-all";
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(`/api/v1/orders/${orderId}`, {
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("/api/v1/orders/batch-create", {
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("/api/v1/orders/batch-replace", {
393
+ return this.makeAuthenticatedRequest(perpRoutes.orders.batchReplace(), {
339
394
  method: "POST",
340
395
  body: JSON.stringify(requestBody),
341
396
  });
@@ -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, trading_pair_id } = params || {};
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);
@@ -389,6 +444,12 @@ export class TradingAPIImpl extends BaseAPI {
389
444
  if (trading_pair_id) {
390
445
  searchParams.append("trading_pair_id", trading_pair_id);
391
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);
452
+ }
392
453
  const endpoint = `/api/v1/orders?${searchParams.toString()}`;
393
454
  return await this.makeAuthenticatedRequest(endpoint, {
394
455
  method: "GET",
@@ -413,7 +474,7 @@ export class TradingAPIImpl extends BaseAPI {
413
474
  * ```
414
475
  */
415
476
  async getOrder(orderId) {
416
- return await this.makeAuthenticatedRequest(`/api/v1/orders/${orderId}`, {
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(() => connect(), delay);
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
- ws = new WebSocket(getUrl());
196
+ const socket = new WebSocket(getUrl());
197
+ ws = socket;
100
198
  const timeout = setTimeout(() => {
101
- if (ws?.readyState === WebSocket.CONNECTING) {
102
- ws.close();
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
- ws.onopen = () => {
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
- ws.onmessage = (event) => {
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
- ws.onclose = (event) => {
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
- ws.onerror = () => clearTimeout(timeout);
248
+ socket.onerror = () => clearTimeout(timeout);
136
249
  }
137
250
  catch (err) {
138
251
  options.onStatusChange?.("disconnected");
@@ -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
- // Reconnect to include token in ws URL
404
- if (ws?.readyState === WebSocket.OPEN || ws?.readyState === WebSocket.CONNECTING) {
405
- ws.close(1000, "Token updated, reconnecting.");
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;
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);
@@ -179,11 +189,9 @@ export class MonacoSDKImpl {
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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@0xmonaco/core",
3
- "version": "0.0.0-develop-20260415185155",
3
+ "version": "0.0.0-develop-20260420223958",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -23,8 +23,8 @@
23
23
  "viem": "^2.45.2"
24
24
  },
25
25
  "dependencies": {
26
- "@0xmonaco/contracts": "0.0.0-develop-20260415185155",
27
- "@0xmonaco/types": "0.0.0-develop-20260415185155",
26
+ "@0xmonaco/contracts": "0.0.0-develop-20260420223958",
27
+ "@0xmonaco/types": "0.0.0-develop-20260420223958",
28
28
  "http-status-codes": "^2.3.0"
29
29
  },
30
30
  "devDependencies": {