@0xmonaco/core 1.1.2-develop.3a25169 → 1.1.5-develop.129b2c6
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/analytics/api.d.ts +40 -0
- package/dist/api/analytics/api.js +107 -0
- package/dist/api/analytics/index.d.ts +1 -0
- package/dist/api/analytics/index.js +1 -0
- package/dist/api/applications/api.d.ts +5 -5
- package/dist/api/applications/api.js +5 -5
- package/dist/api/buildercodes/api.d.ts +18 -11
- package/dist/api/buildercodes/api.js +31 -15
- package/dist/api/index.d.ts +2 -0
- package/dist/api/index.js +2 -0
- package/dist/api/market/api.d.ts +3 -1
- package/dist/api/market/api.js +9 -0
- package/dist/api/orderbook/api.d.ts +5 -2
- package/dist/api/orderbook/api.js +2 -0
- package/dist/api/perp/routes.d.ts +68 -0
- package/dist/api/perp/routes.js +22 -0
- package/dist/api/rfq/api.d.ts +69 -0
- package/dist/api/rfq/api.js +129 -0
- package/dist/api/rfq/index.d.ts +6 -0
- package/dist/api/rfq/index.js +6 -0
- package/dist/api/trades/api.d.ts +24 -0
- package/dist/api/trades/api.js +28 -1
- package/dist/api/trading/api.d.ts +35 -3
- package/dist/api/trading/api.js +49 -7
- package/dist/api/websocket/local-book.d.ts +112 -0
- package/dist/api/websocket/local-book.js +423 -0
- package/dist/api/websocket/websocket.js +790 -38
- package/dist/coverage.d.ts +28 -0
- package/dist/coverage.js +28 -0
- package/dist/sdk.d.ts +3 -1
- package/dist/sdk.js +8 -0
- package/dist/utils/magnitude.d.ts +5 -2
- package/dist/utils/magnitude.js +6 -3
- package/package.json +3 -3
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RFQ (block trading) API Implementation
|
|
3
|
+
*
|
|
4
|
+
* A taker requests quotes for a size; makers quote privately; the taker
|
|
5
|
+
* accepts one side of the best allocation, and each selected maker then has a
|
|
6
|
+
* short last look (reject or improve; silence executes). Available only to
|
|
7
|
+
* accounts RFQ is enabled for: other callers get `403` with code
|
|
8
|
+
* `RFQ_DISABLED`.
|
|
9
|
+
*
|
|
10
|
+
* Every call is signed. Every write carries an `idempotencyKey` (generated
|
|
11
|
+
* when omitted) and is sent as a keyed submission, so a write whose outcome
|
|
12
|
+
* is unknown is resent with the same key and body and the server replays the
|
|
13
|
+
* first result. The body is built key by key from validated params, because
|
|
14
|
+
* the gateway rejects unknown fields and stores a maker's request exactly as
|
|
15
|
+
* signed.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* // Taker
|
|
20
|
+
* const rfq = await sdk.rfq.createRfq({ tradingPairId, product: "PERPETUAL", quantity: "25" });
|
|
21
|
+
* const status = await sdk.rfq.getRfq(rfq.terms!.rfqId);
|
|
22
|
+
* await sdk.rfq.acceptRfq(rfq.terms!.rfqId, { side: "BUY", viewVersion: status.view!.viewVersion });
|
|
23
|
+
*
|
|
24
|
+
* // Maker
|
|
25
|
+
* const quote = await sdk.rfq.upsertQuote(rfqId, { expectedVersion: 0, ask: { price: "65001", capacity: "10" } });
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
import type { AcceptRfqParams, CancelRfqParams, CreateRfqParams, GetRfqCapabilitiesResponse, RespondRfqLastLookParams, RespondRfqLastLookResponse, RfqAPI, RfqQuoteVersion, RfqStatus, UpsertRfqQuoteParams, WithdrawRfqQuoteParams, WithdrawRfqQuoteResponse } from "@0xmonaco/types";
|
|
29
|
+
import { BaseAPI } from "../base";
|
|
30
|
+
export declare class RfqAPIImpl extends BaseAPI implements RfqAPI {
|
|
31
|
+
/** Your RFQ limits and the markets RFQ is offered on. */
|
|
32
|
+
getCapabilities(): Promise<GetRfqCapabilitiesResponse>;
|
|
33
|
+
/**
|
|
34
|
+
* Request quotes for up to `quantity` (not a guaranteed fill). Omit `side`
|
|
35
|
+
* for a two-way RFQ, whose direction stays hidden from makers; set, makers
|
|
36
|
+
* see it and may quote only the side that fills it (`terms.quoteSide`). On a perpetual give `leverage`
|
|
37
|
+
* (and optionally `marginMode`) for the order you accept with, as on an
|
|
38
|
+
* order. Delegated agents cannot request quotes.
|
|
39
|
+
*/
|
|
40
|
+
createRfq(params: CreateRfqParams): Promise<RfqStatus>;
|
|
41
|
+
/**
|
|
42
|
+
* An RFQ's authoritative status. As taker: the current `view` and, once
|
|
43
|
+
* executed, the `outcome`. As maker: your latest quote, `ownLatestVersion`
|
|
44
|
+
* and, once selected, `ownSelection` for last look.
|
|
45
|
+
*/
|
|
46
|
+
getRfq(rfqId: string): Promise<RfqStatus>;
|
|
47
|
+
/**
|
|
48
|
+
* Accept one side of the view you last saw. Binding: the selected makers'
|
|
49
|
+
* last look follows, and silence executes. A newer view refuses an older
|
|
50
|
+
* `viewVersion` (409); read the RFQ again and accept the current one.
|
|
51
|
+
*/
|
|
52
|
+
acceptRfq(rfqId: string, params: AcceptRfqParams): Promise<RfqStatus>;
|
|
53
|
+
/** Cancel an RFQ you have not accepted, before its deadline. */
|
|
54
|
+
cancelRfq(rfqId: string, params?: CancelRfqParams): Promise<RfqStatus>;
|
|
55
|
+
/**
|
|
56
|
+
* As maker: place or replace your quote, a bid, an ask or both. Name your
|
|
57
|
+
* current version (`ownLatestVersion`; 0 for your first quote); a stale
|
|
58
|
+
* version is refused (409).
|
|
59
|
+
*/
|
|
60
|
+
upsertQuote(rfqId: string, params: UpsertRfqQuoteParams): Promise<RfqQuoteVersion>;
|
|
61
|
+
/** As maker: withdraw your current quote, naming your current version. */
|
|
62
|
+
withdrawQuote(rfqId: string, params: WithdrawRfqQuoteParams): Promise<WithdrawRfqQuoteResponse>;
|
|
63
|
+
/**
|
|
64
|
+
* As a selected maker: reject, or improve your frozen terms (a strictly
|
|
65
|
+
* better price or a higher capacity), before the last-look deadline. There
|
|
66
|
+
* is no accept: silence executes.
|
|
67
|
+
*/
|
|
68
|
+
respondLastLook(rfqId: string, params: RespondRfqLastLookParams): Promise<RespondRfqLastLookResponse>;
|
|
69
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RFQ (block trading) API Implementation
|
|
3
|
+
*
|
|
4
|
+
* A taker requests quotes for a size; makers quote privately; the taker
|
|
5
|
+
* accepts one side of the best allocation, and each selected maker then has a
|
|
6
|
+
* short last look (reject or improve; silence executes). Available only to
|
|
7
|
+
* accounts RFQ is enabled for: other callers get `403` with code
|
|
8
|
+
* `RFQ_DISABLED`.
|
|
9
|
+
*
|
|
10
|
+
* Every call is signed. Every write carries an `idempotencyKey` (generated
|
|
11
|
+
* when omitted) and is sent as a keyed submission, so a write whose outcome
|
|
12
|
+
* is unknown is resent with the same key and body and the server replays the
|
|
13
|
+
* first result. The body is built key by key from validated params, because
|
|
14
|
+
* the gateway rejects unknown fields and stores a maker's request exactly as
|
|
15
|
+
* signed.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* // Taker
|
|
20
|
+
* const rfq = await sdk.rfq.createRfq({ tradingPairId, product: "PERPETUAL", quantity: "25" });
|
|
21
|
+
* const status = await sdk.rfq.getRfq(rfq.terms!.rfqId);
|
|
22
|
+
* await sdk.rfq.acceptRfq(rfq.terms!.rfqId, { side: "BUY", viewVersion: status.view!.viewVersion });
|
|
23
|
+
*
|
|
24
|
+
* // Maker
|
|
25
|
+
* const quote = await sdk.rfq.upsertQuote(rfqId, { expectedVersion: 0, ask: { price: "65001", capacity: "10" } });
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
import { AcceptRfqSchema, CancelRfqSchema, CreateRfqSchema, RespondRfqLastLookSchema, UpsertRfqQuoteSchema, UUIDSchema, validate, WithdrawRfqQuoteSchema, } from "@0xmonaco/types";
|
|
29
|
+
import { BaseAPI } from "../base";
|
|
30
|
+
const BASE = "/api/v1/rfqs";
|
|
31
|
+
/** The RFQ path for a validated RFQ id. */
|
|
32
|
+
function rfqPath(rfqId) {
|
|
33
|
+
return `${BASE}/${validate(UUIDSchema, rfqId)}`;
|
|
34
|
+
}
|
|
35
|
+
/** The caller's key, or a fresh one. */
|
|
36
|
+
function keyOf(idempotencyKey) {
|
|
37
|
+
return idempotencyKey ?? crypto.randomUUID();
|
|
38
|
+
}
|
|
39
|
+
export class RfqAPIImpl extends BaseAPI {
|
|
40
|
+
/** Your RFQ limits and the markets RFQ is offered on. */
|
|
41
|
+
async getCapabilities() {
|
|
42
|
+
return await this.makeAuthenticatedRequest("/api/v1/rfq/capabilities", { method: "GET" });
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Request quotes for up to `quantity` (not a guaranteed fill). Omit `side`
|
|
46
|
+
* for a two-way RFQ, whose direction stays hidden from makers; set, makers
|
|
47
|
+
* see it and may quote only the side that fills it (`terms.quoteSide`). On a perpetual give `leverage`
|
|
48
|
+
* (and optionally `marginMode`) for the order you accept with, as on an
|
|
49
|
+
* order. Delegated agents cannot request quotes.
|
|
50
|
+
*/
|
|
51
|
+
async createRfq(params) {
|
|
52
|
+
const { tradingPairId, product, quantity, side, leverage, marginMode, idempotencyKey } = validate(CreateRfqSchema, params);
|
|
53
|
+
const body = { idempotencyKey: keyOf(idempotencyKey), tradingPairId, product, quantity };
|
|
54
|
+
if (side !== undefined)
|
|
55
|
+
body.side = side;
|
|
56
|
+
if (leverage !== undefined)
|
|
57
|
+
body.leverage = leverage;
|
|
58
|
+
if (marginMode !== undefined)
|
|
59
|
+
body.marginMode = marginMode;
|
|
60
|
+
return await this.makeKeyedSubmission(BASE, { method: "POST", body: JSON.stringify(body) });
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* An RFQ's authoritative status. As taker: the current `view` and, once
|
|
64
|
+
* executed, the `outcome`. As maker: your latest quote, `ownLatestVersion`
|
|
65
|
+
* and, once selected, `ownSelection` for last look.
|
|
66
|
+
*/
|
|
67
|
+
async getRfq(rfqId) {
|
|
68
|
+
return await this.makeAuthenticatedRequest(rfqPath(rfqId), { method: "GET" });
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Accept one side of the view you last saw. Binding: the selected makers'
|
|
72
|
+
* last look follows, and silence executes. A newer view refuses an older
|
|
73
|
+
* `viewVersion` (409); read the RFQ again and accept the current one.
|
|
74
|
+
*/
|
|
75
|
+
async acceptRfq(rfqId, params) {
|
|
76
|
+
const path = rfqPath(rfqId);
|
|
77
|
+
const { side, viewVersion, idempotencyKey } = validate(AcceptRfqSchema, params);
|
|
78
|
+
const body = { idempotencyKey: keyOf(idempotencyKey), side, viewVersion };
|
|
79
|
+
return await this.makeKeyedSubmission(`${path}/accept`, { method: "POST", body: JSON.stringify(body) });
|
|
80
|
+
}
|
|
81
|
+
/** Cancel an RFQ you have not accepted, before its deadline. */
|
|
82
|
+
async cancelRfq(rfqId, params = {}) {
|
|
83
|
+
const path = rfqPath(rfqId);
|
|
84
|
+
const { idempotencyKey } = validate(CancelRfqSchema, params);
|
|
85
|
+
const body = { idempotencyKey: keyOf(idempotencyKey) };
|
|
86
|
+
return await this.makeKeyedSubmission(`${path}/cancel`, { method: "POST", body: JSON.stringify(body) });
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* As maker: place or replace your quote, a bid, an ask or both. Name your
|
|
90
|
+
* current version (`ownLatestVersion`; 0 for your first quote); a stale
|
|
91
|
+
* version is refused (409).
|
|
92
|
+
*/
|
|
93
|
+
async upsertQuote(rfqId, params) {
|
|
94
|
+
const path = rfqPath(rfqId);
|
|
95
|
+
const { expectedVersion, bid, ask, validityMs, leverage, marginMode, idempotencyKey } = validate(UpsertRfqQuoteSchema, params);
|
|
96
|
+
const body = { idempotencyKey: keyOf(idempotencyKey), expectedVersion };
|
|
97
|
+
if (bid !== undefined)
|
|
98
|
+
body.bid = { price: bid.price, capacity: bid.capacity };
|
|
99
|
+
if (ask !== undefined)
|
|
100
|
+
body.ask = { price: ask.price, capacity: ask.capacity };
|
|
101
|
+
if (validityMs !== undefined)
|
|
102
|
+
body.validityMs = validityMs;
|
|
103
|
+
if (leverage !== undefined)
|
|
104
|
+
body.leverage = leverage;
|
|
105
|
+
if (marginMode !== undefined)
|
|
106
|
+
body.marginMode = marginMode;
|
|
107
|
+
return await this.makeKeyedSubmission(`${path}/quote`, { method: "PUT", body: JSON.stringify(body) });
|
|
108
|
+
}
|
|
109
|
+
/** As maker: withdraw your current quote, naming your current version. */
|
|
110
|
+
async withdrawQuote(rfqId, params) {
|
|
111
|
+
const path = rfqPath(rfqId);
|
|
112
|
+
const { expectedVersion, idempotencyKey } = validate(WithdrawRfqQuoteSchema, params);
|
|
113
|
+
const body = { idempotencyKey: keyOf(idempotencyKey), expectedVersion };
|
|
114
|
+
return await this.makeKeyedSubmission(`${path}/quote`, { method: "DELETE", body: JSON.stringify(body) });
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* As a selected maker: reject, or improve your frozen terms (a strictly
|
|
118
|
+
* better price or a higher capacity), before the last-look deadline. There
|
|
119
|
+
* is no accept: silence executes.
|
|
120
|
+
*/
|
|
121
|
+
async respondLastLook(rfqId, params) {
|
|
122
|
+
const path = rfqPath(rfqId);
|
|
123
|
+
const { acceptanceId, response, improvedTerms, idempotencyKey } = validate(RespondRfqLastLookSchema, params);
|
|
124
|
+
const body = { idempotencyKey: keyOf(idempotencyKey), acceptanceId, response };
|
|
125
|
+
if (improvedTerms !== undefined)
|
|
126
|
+
body.improvedTerms = { price: improvedTerms.price, capacity: improvedTerms.capacity };
|
|
127
|
+
return await this.makeKeyedSubmission(`${path}/last-look`, { method: "POST", body: JSON.stringify(body) });
|
|
128
|
+
}
|
|
129
|
+
}
|
package/dist/api/trades/api.d.ts
CHANGED
|
@@ -16,6 +16,13 @@ interface RawTradeEvent {
|
|
|
16
16
|
makerSide: string;
|
|
17
17
|
/** Absent when the trade has no recorded execution time */
|
|
18
18
|
executedAt?: string;
|
|
19
|
+
/** CLOB or RFQ */
|
|
20
|
+
executionSource?: string;
|
|
21
|
+
makerAddress?: string;
|
|
22
|
+
takerAddress?: string;
|
|
23
|
+
takerFeeRaw?: string;
|
|
24
|
+
quoteVolumeRaw?: string;
|
|
25
|
+
takerApplicationId?: string;
|
|
19
26
|
};
|
|
20
27
|
}
|
|
21
28
|
/**
|
|
@@ -34,6 +41,13 @@ export interface GetTradesOptions {
|
|
|
34
41
|
*/
|
|
35
42
|
pageToken?: string;
|
|
36
43
|
}
|
|
44
|
+
/**
|
|
45
|
+
* Options for the every-market trade feed.
|
|
46
|
+
*/
|
|
47
|
+
export interface ListTradesOptions extends GetTradesOptions {
|
|
48
|
+
/** Only the trades this application (frontend) took, as the taker's application. */
|
|
49
|
+
takerApplicationId?: string;
|
|
50
|
+
}
|
|
37
51
|
/**
|
|
38
52
|
* One page of a pair's trade feed.
|
|
39
53
|
*
|
|
@@ -74,6 +88,16 @@ export declare class TradesAPIImpl extends BaseAPI {
|
|
|
74
88
|
* ```
|
|
75
89
|
*/
|
|
76
90
|
getTrades(tradingPairId: string, options?: GetTradesOptions): Promise<GetTradesPage>;
|
|
91
|
+
/**
|
|
92
|
+
* Get one page of the trade feed: every market, newest first, recent and
|
|
93
|
+
* archived trades alike, or only the trades one application took when
|
|
94
|
+
* `takerApplicationId` is set. Each trade carries both wallets, the raw taker
|
|
95
|
+
* fee and quote volume, and the taker's application.
|
|
96
|
+
*
|
|
97
|
+
* Public; each client IP has a read budget (HTTP 429 over it). Start with no
|
|
98
|
+
* `pageToken` and follow `nextPageToken` until it comes back empty.
|
|
99
|
+
*/
|
|
100
|
+
listTrades(options?: ListTradesOptions): Promise<GetTradesPage>;
|
|
77
101
|
/**
|
|
78
102
|
* Get a single trade by its UUID.
|
|
79
103
|
*
|
package/dist/api/trades/api.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { GetTradesSchema, validate } from "@0xmonaco/types";
|
|
1
|
+
import { GetTradesSchema, ListTradesSchema, validate } from "@0xmonaco/types";
|
|
2
2
|
import { BaseAPI } from "../base";
|
|
3
3
|
import { perpRoutes } from "../perp";
|
|
4
4
|
/**
|
|
@@ -15,6 +15,12 @@ export function parseRawTradeEvent(raw) {
|
|
|
15
15
|
quantity: raw.data.quantity,
|
|
16
16
|
makerSide: raw.data.makerSide.toUpperCase(),
|
|
17
17
|
executedAt: raw.data.executedAt ?? "",
|
|
18
|
+
...(raw.data.executionSource ? { executionSource: raw.data.executionSource } : {}),
|
|
19
|
+
...(raw.data.makerAddress ? { makerAddress: raw.data.makerAddress } : {}),
|
|
20
|
+
...(raw.data.takerAddress ? { takerAddress: raw.data.takerAddress } : {}),
|
|
21
|
+
...(raw.data.takerFeeRaw ? { takerFeeRaw: raw.data.takerFeeRaw } : {}),
|
|
22
|
+
...(raw.data.quoteVolumeRaw ? { quoteVolumeRaw: raw.data.quoteVolumeRaw } : {}),
|
|
23
|
+
...(raw.data.takerApplicationId ? { takerApplicationId: raw.data.takerApplicationId } : {}),
|
|
18
24
|
},
|
|
19
25
|
};
|
|
20
26
|
}
|
|
@@ -67,6 +73,27 @@ export class TradesAPIImpl extends BaseAPI {
|
|
|
67
73
|
nextPageToken: response.nextPageToken ?? "",
|
|
68
74
|
};
|
|
69
75
|
}
|
|
76
|
+
/**
|
|
77
|
+
* Get one page of the trade feed: every market, newest first, recent and
|
|
78
|
+
* archived trades alike, or only the trades one application took when
|
|
79
|
+
* `takerApplicationId` is set. Each trade carries both wallets, the raw taker
|
|
80
|
+
* fee and quote volume, and the taker's application.
|
|
81
|
+
*
|
|
82
|
+
* Public; each client IP has a read budget (HTTP 429 over it). Start with no
|
|
83
|
+
* `pageToken` and follow `nextPageToken` until it comes back empty.
|
|
84
|
+
*/
|
|
85
|
+
async listTrades(options = {}) {
|
|
86
|
+
validate(ListTradesSchema, options);
|
|
87
|
+
const response = await this.makePublicRequest(perpRoutes.trades.feed({
|
|
88
|
+
...(options.takerApplicationId ? { takerApplicationId: options.takerApplicationId } : {}),
|
|
89
|
+
...(options.pageSize != null ? { pageSize: options.pageSize } : {}),
|
|
90
|
+
...(options.pageToken ? { pageToken: options.pageToken } : {}),
|
|
91
|
+
}));
|
|
92
|
+
return {
|
|
93
|
+
trades: (response.trades ?? []).map(parseRawTradeEvent),
|
|
94
|
+
nextPageToken: response.nextPageToken ?? "",
|
|
95
|
+
};
|
|
96
|
+
}
|
|
70
97
|
/**
|
|
71
98
|
* Get a single trade by its UUID.
|
|
72
99
|
*
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
* );
|
|
22
22
|
* ```
|
|
23
23
|
*/
|
|
24
|
-
import type { BatchCancelOrdersResponse, BatchCreateOrderParams, BatchCreateOrdersResponse, BatchReplaceOrderParams, BatchReplaceOrdersResponse, CancelConditionalOrderResponse, CancelOrderResponse, CancelTwapOrderResponse, ConditionalOrder, CreateOrderResponse, CreateTwapOrderOptions, CreateTwapOrderResponse, GetOrderResponse, GetPaginatedOrdersParams, GetPaginatedOrdersResponse, GetTwapOrderTcaResponse, ListConditionalOrdersParams, ListConditionalOrdersResponse, ListTwapOrderSlicesParams, ListTwapOrderSlicesResponse, ListTwapOrdersParams, ListTwapOrdersResponse, MarginMode, OrderSide, ParentTpSlLegParams, ParentTrailingStopLegParams, PositionSide, ReplaceOrderResponse, SelfTradePreventionMode, TimeInForce, TradingAPI, TradingMode, TwapOrder } from "@0xmonaco/types";
|
|
24
|
+
import type { BatchCancelOrdersResponse, BatchCreateOrderParams, BatchCreateOrdersResponse, BatchReplaceOrderParams, BatchReplaceOrdersResponse, CancelAllAfterOptions, CancelAllAfterResponse, CancelConditionalOrderResponse, CancelOrderResponse, CancelTwapOrderResponse, ConditionalOrder, CreateOrderResponse, CreateTwapOrderOptions, CreateTwapOrderResponse, GetOrderResponse, GetPaginatedOrdersParams, GetPaginatedOrdersResponse, GetTwapOrderTcaResponse, ListConditionalOrdersParams, ListConditionalOrdersResponse, ListTwapOrderSlicesParams, ListTwapOrderSlicesResponse, ListTwapOrdersParams, ListTwapOrdersResponse, MarginMode, OrderSide, ParentTpSlLegParams, ParentTrailingStopLegParams, PositionSide, ReplaceOrderResponse, SelfTradePreventionMode, TimeInForce, TradingAPI, TradingMode, TwapOrder } from "@0xmonaco/types";
|
|
25
25
|
import { BaseAPI } from "../base";
|
|
26
26
|
export declare class TradingAPIImpl extends BaseAPI implements TradingAPI {
|
|
27
27
|
/**
|
|
@@ -41,7 +41,7 @@ export declare class TradingAPIImpl extends BaseAPI implements TradingAPI {
|
|
|
41
41
|
* @param quantity - The order quantity as string
|
|
42
42
|
* @param price - The limit price as string
|
|
43
43
|
* @param options - Optional parameters for the limit order
|
|
44
|
-
* @param options.tradingMode - Trading mode (
|
|
44
|
+
* @param options.tradingMode - Trading mode ("SPOT" or "MARGIN"). Omit it to use the trading pair market type.
|
|
45
45
|
* @param options.useMasterBalance - Whether to use master balance for sub-accounts
|
|
46
46
|
* @param options.expirationDate - Optional expiration date for GTC orders (ISO 8601 format)
|
|
47
47
|
* @param options.timeInForce - Time in force ("GTC", "IOC", or "FOK")
|
|
@@ -115,7 +115,7 @@ export declare class TradingAPIImpl extends BaseAPI implements TradingAPI {
|
|
|
115
115
|
* @param side - The order side ("BUY" or "SELL")
|
|
116
116
|
* @param quantity - The order quantity as string
|
|
117
117
|
* @param options - Optional parameters for the market order
|
|
118
|
-
* @param options.tradingMode - Trading mode (
|
|
118
|
+
* @param options.tradingMode - Trading mode ("SPOT" or "MARGIN"). Omit it to use the trading pair market type.
|
|
119
119
|
* @param options.slippageTolerance - Tightens the mandatory 1,000 bps price band, as a decimal (e.g., 0.01 for 1%; 0 for best price only). It can only tighten the band, never widen it; omitting it applies the full 1,000 bps band.
|
|
120
120
|
* @returns Promise resolving to CreateOrderResponse with order details
|
|
121
121
|
*
|
|
@@ -241,6 +241,38 @@ export declare class TradingAPIImpl extends BaseAPI implements TradingAPI {
|
|
|
241
241
|
* ```
|
|
242
242
|
*/
|
|
243
243
|
batchCancelAll(tradingPairId?: string): Promise<BatchCancelOrdersResponse>;
|
|
244
|
+
/**
|
|
245
|
+
* Arms, refreshes or disarms a dead man's switch.
|
|
246
|
+
*
|
|
247
|
+
* Unless you call again before `timeoutMs` runs out, the exchange cancels
|
|
248
|
+
* your resting orders with terminalReason `CANCEL_ALL_AFTER`. Call it on an
|
|
249
|
+
* interval shorter than the timeout to keep pushing the deadline out; send
|
|
250
|
+
* 0 to disarm. A timer that fires is spent, so arm it again afterwards.
|
|
251
|
+
*
|
|
252
|
+
* @param timeoutMs - 0 disarms; otherwise 5000 to 900000 (5 s to 15 min)
|
|
253
|
+
* @param options - Optional `tradingPairId` to scope the timer to one market
|
|
254
|
+
* @returns Promise resolving to the deadline that was set
|
|
255
|
+
* @throws {ValidationError} When the timeout or trading pair id is invalid
|
|
256
|
+
* @throws {APIError} When API communication fails
|
|
257
|
+
*
|
|
258
|
+
* @example
|
|
259
|
+
* ```typescript
|
|
260
|
+
* // Cancel everything if this process stops refreshing for 30 seconds.
|
|
261
|
+
* const { cancelAt } = await tradingAPI.cancelAllAfter(30_000);
|
|
262
|
+
* // One refresh at a time, each after the previous call settles.
|
|
263
|
+
* let pending: Promise<unknown> = Promise.resolve();
|
|
264
|
+
* const refresh = setInterval(() => {
|
|
265
|
+
* pending = pending.then(() => tradingAPI.cancelAllAfter(30_000)).catch(() => undefined);
|
|
266
|
+
* }, 10_000);
|
|
267
|
+
*
|
|
268
|
+
* // Clean shutdown: let the last refresh settle before disarming, or it
|
|
269
|
+
* // could land after the disarm and re-arm the timer.
|
|
270
|
+
* clearInterval(refresh);
|
|
271
|
+
* await pending;
|
|
272
|
+
* await tradingAPI.cancelAllAfter(0);
|
|
273
|
+
* ```
|
|
274
|
+
*/
|
|
275
|
+
cancelAllAfter(timeoutMs: number, options?: CancelAllAfterOptions): Promise<CancelAllAfterResponse>;
|
|
244
276
|
replaceOrder(orderId: string, newOrder: {
|
|
245
277
|
price?: string;
|
|
246
278
|
quantity?: string;
|
package/dist/api/trading/api.js
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
* );
|
|
22
22
|
* ```
|
|
23
23
|
*/
|
|
24
|
-
import { BatchCreateOrdersSchema, BatchReplaceOrdersSchema, CancelConditionalOrderSchema, CancelOrderSchema, CancelTwapOrderSchema, CreateTwapOrderSchema, GetPaginatedOrdersSchema, ListConditionalOrdersSchema, ListTwapOrderSlicesSchema, ListTwapOrdersSchema, PlaceLimitOrderSchema, PlaceMarketOrderSchema, ReplaceOrderSchema, validate, } from "@0xmonaco/types";
|
|
24
|
+
import { BatchCreateOrdersSchema, BatchReplaceOrdersSchema, CancelAllAfterSchema, CancelConditionalOrderSchema, CancelOrderSchema, CancelTwapOrderSchema, CreateTwapOrderSchema, GetPaginatedOrdersSchema, ListConditionalOrdersSchema, ListTwapOrderSlicesSchema, ListTwapOrdersSchema, PlaceLimitOrderSchema, PlaceMarketOrderSchema, ReplaceOrderSchema, validate, } from "@0xmonaco/types";
|
|
25
25
|
import { BaseAPI } from "../base";
|
|
26
26
|
import { perpRoutes } from "../perp";
|
|
27
27
|
function parentTpSlLegToRequest(leg) {
|
|
@@ -77,7 +77,7 @@ export class TradingAPIImpl extends BaseAPI {
|
|
|
77
77
|
* @param quantity - The order quantity as string
|
|
78
78
|
* @param price - The limit price as string
|
|
79
79
|
* @param options - Optional parameters for the limit order
|
|
80
|
-
* @param options.tradingMode - Trading mode (
|
|
80
|
+
* @param options.tradingMode - Trading mode ("SPOT" or "MARGIN"). Omit it to use the trading pair market type.
|
|
81
81
|
* @param options.useMasterBalance - Whether to use master balance for sub-accounts
|
|
82
82
|
* @param options.expirationDate - Optional expiration date for GTC orders (ISO 8601 format)
|
|
83
83
|
* @param options.timeInForce - Time in force ("GTC", "IOC", or "FOK")
|
|
@@ -131,7 +131,7 @@ export class TradingAPIImpl extends BaseAPI {
|
|
|
131
131
|
side,
|
|
132
132
|
price,
|
|
133
133
|
quantity,
|
|
134
|
-
tradingMode: options?.tradingMode
|
|
134
|
+
tradingMode: options?.tradingMode,
|
|
135
135
|
useMasterBalance: options?.useMasterBalance,
|
|
136
136
|
expirationDate: options?.expirationDate,
|
|
137
137
|
timeInForce: options?.timeInForce,
|
|
@@ -165,7 +165,7 @@ export class TradingAPIImpl extends BaseAPI {
|
|
|
165
165
|
* @param side - The order side ("BUY" or "SELL")
|
|
166
166
|
* @param quantity - The order quantity as string
|
|
167
167
|
* @param options - Optional parameters for the market order
|
|
168
|
-
* @param options.tradingMode - Trading mode (
|
|
168
|
+
* @param options.tradingMode - Trading mode ("SPOT" or "MARGIN"). Omit it to use the trading pair market type.
|
|
169
169
|
* @param options.slippageTolerance - Tightens the mandatory 1,000 bps price band, as a decimal (e.g., 0.01 for 1%; 0 for best price only). It can only tighten the band, never widen it; omitting it applies the full 1,000 bps band.
|
|
170
170
|
* @returns Promise resolving to CreateOrderResponse with order details
|
|
171
171
|
*
|
|
@@ -211,7 +211,7 @@ export class TradingAPIImpl extends BaseAPI {
|
|
|
211
211
|
slippageToleranceBps: options?.slippageTolerance !== undefined ? Math.round(options.slippageTolerance * 10000) : undefined,
|
|
212
212
|
price: null, // Market orders don't need price
|
|
213
213
|
quantity,
|
|
214
|
-
tradingMode: options?.tradingMode
|
|
214
|
+
tradingMode: options?.tradingMode,
|
|
215
215
|
marginAccountId: options?.marginAccountId,
|
|
216
216
|
marginMode: options?.marginMode,
|
|
217
217
|
riskBucketId: options?.riskBucketId,
|
|
@@ -353,6 +353,48 @@ export class TradingAPIImpl extends BaseAPI {
|
|
|
353
353
|
method: "POST",
|
|
354
354
|
});
|
|
355
355
|
}
|
|
356
|
+
/**
|
|
357
|
+
* Arms, refreshes or disarms a dead man's switch.
|
|
358
|
+
*
|
|
359
|
+
* Unless you call again before `timeoutMs` runs out, the exchange cancels
|
|
360
|
+
* your resting orders with terminalReason `CANCEL_ALL_AFTER`. Call it on an
|
|
361
|
+
* interval shorter than the timeout to keep pushing the deadline out; send
|
|
362
|
+
* 0 to disarm. A timer that fires is spent, so arm it again afterwards.
|
|
363
|
+
*
|
|
364
|
+
* @param timeoutMs - 0 disarms; otherwise 5000 to 900000 (5 s to 15 min)
|
|
365
|
+
* @param options - Optional `tradingPairId` to scope the timer to one market
|
|
366
|
+
* @returns Promise resolving to the deadline that was set
|
|
367
|
+
* @throws {ValidationError} When the timeout or trading pair id is invalid
|
|
368
|
+
* @throws {APIError} When API communication fails
|
|
369
|
+
*
|
|
370
|
+
* @example
|
|
371
|
+
* ```typescript
|
|
372
|
+
* // Cancel everything if this process stops refreshing for 30 seconds.
|
|
373
|
+
* const { cancelAt } = await tradingAPI.cancelAllAfter(30_000);
|
|
374
|
+
* // One refresh at a time, each after the previous call settles.
|
|
375
|
+
* let pending: Promise<unknown> = Promise.resolve();
|
|
376
|
+
* const refresh = setInterval(() => {
|
|
377
|
+
* pending = pending.then(() => tradingAPI.cancelAllAfter(30_000)).catch(() => undefined);
|
|
378
|
+
* }, 10_000);
|
|
379
|
+
*
|
|
380
|
+
* // Clean shutdown: let the last refresh settle before disarming, or it
|
|
381
|
+
* // could land after the disarm and re-arm the timer.
|
|
382
|
+
* clearInterval(refresh);
|
|
383
|
+
* await pending;
|
|
384
|
+
* await tradingAPI.cancelAllAfter(0);
|
|
385
|
+
* ```
|
|
386
|
+
*/
|
|
387
|
+
async cancelAllAfter(timeoutMs, options) {
|
|
388
|
+
validate(CancelAllAfterSchema, { timeoutMs, options });
|
|
389
|
+
const body = { timeoutMs };
|
|
390
|
+
if (options?.tradingPairId !== undefined) {
|
|
391
|
+
body.tradingPairId = options.tradingPairId;
|
|
392
|
+
}
|
|
393
|
+
return this.makeAuthenticatedRequest(perpRoutes.orders.cancelAllAfter(), {
|
|
394
|
+
method: "POST",
|
|
395
|
+
body: JSON.stringify(body),
|
|
396
|
+
});
|
|
397
|
+
}
|
|
356
398
|
async replaceOrder(orderId, newOrder) {
|
|
357
399
|
// Validate inputs before making API call
|
|
358
400
|
validate(ReplaceOrderSchema, { orderId, newOrder });
|
|
@@ -418,7 +460,7 @@ export class TradingAPIImpl extends BaseAPI {
|
|
|
418
460
|
side: order.side,
|
|
419
461
|
price: order.price,
|
|
420
462
|
quantity: order.quantity,
|
|
421
|
-
tradingMode: order.tradingMode
|
|
463
|
+
tradingMode: order.tradingMode,
|
|
422
464
|
slippageToleranceBps: order.slippageTolerance !== undefined ? Math.round(order.slippageTolerance * 10000) : undefined,
|
|
423
465
|
useMasterBalance: order.useMasterBalance,
|
|
424
466
|
expirationDate: order.expirationDate,
|
|
@@ -719,7 +761,7 @@ export class TradingAPIImpl extends BaseAPI {
|
|
|
719
761
|
slippageToleranceBps: options.slippageToleranceBps,
|
|
720
762
|
randomize: options.randomize,
|
|
721
763
|
reduceOnly: options.reduceOnly,
|
|
722
|
-
tradingMode: options.tradingMode
|
|
764
|
+
tradingMode: options.tradingMode,
|
|
723
765
|
marginAccountId: options.marginAccountId,
|
|
724
766
|
riskBucketId: options.riskBucketId,
|
|
725
767
|
marginMode: options.marginMode,
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local depth book and BBO state for the market-data `depth` / `bbo`
|
|
3
|
+
* WebSocket channels (0XM-3551).
|
|
4
|
+
*
|
|
5
|
+
* Handoff rules (the server enforces them; the client checks defensively):
|
|
6
|
+
* - A Snapshot replaces the local state, including mid-stream.
|
|
7
|
+
* - A frame with `book_seq <=` the current sequence is stale or a duplicate
|
|
8
|
+
* and is dropped.
|
|
9
|
+
* - Every kept frame must have `prev_book_seq <=` the current sequence (the
|
|
10
|
+
* snapshot's for the first frame, else the last applied frame's): a delta
|
|
11
|
+
* restates every level changed since its link, so it may link below the
|
|
12
|
+
* previous frame. A frame that links above it means a lost frame: rebuild
|
|
13
|
+
* from a new snapshot.
|
|
14
|
+
* - A BBO frame carries the whole top of book, so any frame newer than the
|
|
15
|
+
* state applies without a link check.
|
|
16
|
+
* - Frames that arrive before the snapshot are buffered and replayed through
|
|
17
|
+
* the same rules once it lands.
|
|
18
|
+
* - On a side whose snapshot was not complete, levels beyond its deepest
|
|
19
|
+
* returned level are unknown, so the book keeps only levels at or better
|
|
20
|
+
* than that boundary.
|
|
21
|
+
*
|
|
22
|
+
* Sequences are u64 durable-log positions, held as decimal strings and
|
|
23
|
+
* compared as `BigInt`.
|
|
24
|
+
*/
|
|
25
|
+
import type { Bbo, BboEvent, BboSnapshot, DepthBook, DepthDelta, DepthSnapshot } from "@0xmonaco/types";
|
|
26
|
+
/**
|
|
27
|
+
* Quote the market-data sequence numbers in a raw frame before `JSON.parse`,
|
|
28
|
+
* so a u64 above `Number.MAX_SAFE_INTEGER` survives exactly. Only the
|
|
29
|
+
* unescaped `"book_seq":` / `"prev_book_seq":` keys followed by an integer are
|
|
30
|
+
* touched; inside a JSON string those quotes would be escaped.
|
|
31
|
+
*/
|
|
32
|
+
export declare function quoteSequenceNumbers(raw: string): string;
|
|
33
|
+
/**
|
|
34
|
+
* {@link readSequence} that leaves an absent or malformed value `undefined`
|
|
35
|
+
* instead of throwing. A JSON number counts only while it is still exact (a
|
|
36
|
+
* quoted integer always does), so a rounded u64 never passes for a precise one.
|
|
37
|
+
*/
|
|
38
|
+
export declare function tryReadSequence(data: Record<string, unknown>, key: string): string | undefined;
|
|
39
|
+
export declare function parseDepthSnapshot(raw: unknown): DepthSnapshot;
|
|
40
|
+
export declare function parseDepthDelta(raw: unknown): DepthDelta;
|
|
41
|
+
export declare function parseBboSnapshot(raw: unknown): BboSnapshot;
|
|
42
|
+
export declare function parseBboEvent(raw: unknown): BboEvent;
|
|
43
|
+
/** Compare two non-negative decimal strings numerically. */
|
|
44
|
+
export declare function compareDecimal(a: string, b: string): number;
|
|
45
|
+
/** The result of offering a frame to the local state. */
|
|
46
|
+
export type FrameOutcome =
|
|
47
|
+
/** Applied; the state moved forward. */
|
|
48
|
+
"applied"
|
|
49
|
+
/** Held until the snapshot arrives. */
|
|
50
|
+
| "buffered"
|
|
51
|
+
/** Stale or a duplicate. */
|
|
52
|
+
| "dropped"
|
|
53
|
+
/** Did not link: a frame was lost. */
|
|
54
|
+
| "gap"
|
|
55
|
+
/** Applied, but a side whose snapshot was incomplete is now empty: its remainder is unknown. */
|
|
56
|
+
| "truncated";
|
|
57
|
+
/** The result of applying a snapshot (with any buffered frames replayed). */
|
|
58
|
+
export type SnapshotOutcome = "applied" | "gap" | "truncated";
|
|
59
|
+
/**
|
|
60
|
+
* The sequence guard shared by `depth` and `bbo`: snapshot replaces, stale
|
|
61
|
+
* frames drop, a frame linking above the current sequence is a gap, frames
|
|
62
|
+
* before the snapshot buffer.
|
|
63
|
+
*/
|
|
64
|
+
declare abstract class SequencedState<Snapshot extends {
|
|
65
|
+
bookSeq: string;
|
|
66
|
+
}, Frame extends {
|
|
67
|
+
bookSeq: string;
|
|
68
|
+
prevBookSeq: string;
|
|
69
|
+
}> {
|
|
70
|
+
private current;
|
|
71
|
+
private buffered;
|
|
72
|
+
/**
|
|
73
|
+
* Whether a frame must link to the current state. Depth deltas carry only
|
|
74
|
+
* changed levels, so a frame past a lost one is a gap; a BBO frame carries
|
|
75
|
+
* the whole top of book, so any newer one is complete on its own.
|
|
76
|
+
*/
|
|
77
|
+
protected readonly checksLinks: boolean;
|
|
78
|
+
/** Whether a snapshot has been applied since the last reset. */
|
|
79
|
+
get ready(): boolean;
|
|
80
|
+
protected abstract resetFrom(snapshot: Snapshot): void;
|
|
81
|
+
protected abstract applyFrame(frame: Frame): void;
|
|
82
|
+
/** Whether the state can no longer be trusted past its known levels (see `"truncated"`). */
|
|
83
|
+
protected truncated(): boolean;
|
|
84
|
+
/** Replace the state with `snapshot`, then replay buffered frames. Returns `"gap"` if a buffered frame does not link. */
|
|
85
|
+
applySnapshot(snapshot: Snapshot): SnapshotOutcome;
|
|
86
|
+
/** Offer a live frame. */
|
|
87
|
+
offer(frame: Frame): FrameOutcome;
|
|
88
|
+
/** Discard everything; the next snapshot starts over. */
|
|
89
|
+
reset(): void;
|
|
90
|
+
}
|
|
91
|
+
/** The local depth book for one `depth` channel. */
|
|
92
|
+
export declare class LocalDepthBook extends SequencedState<DepthSnapshot, DepthDelta> {
|
|
93
|
+
private readonly bids;
|
|
94
|
+
private readonly asks;
|
|
95
|
+
private header;
|
|
96
|
+
protected resetFrom(snapshot: DepthSnapshot): void;
|
|
97
|
+
protected applyFrame(frame: DepthDelta): void;
|
|
98
|
+
protected truncated(): boolean;
|
|
99
|
+
reset(): void;
|
|
100
|
+
/** The current book, or `null` before a snapshot. */
|
|
101
|
+
view(): DepthBook | null;
|
|
102
|
+
}
|
|
103
|
+
/** The local top of book for one `bbo` channel. */
|
|
104
|
+
export declare class LocalBbo extends SequencedState<BboSnapshot, BboEvent> {
|
|
105
|
+
protected readonly checksLinks = false;
|
|
106
|
+
private state;
|
|
107
|
+
protected resetFrom(snapshot: BboSnapshot): void;
|
|
108
|
+
protected applyFrame(frame: BboEvent): void;
|
|
109
|
+
reset(): void;
|
|
110
|
+
view(): Bbo | null;
|
|
111
|
+
}
|
|
112
|
+
export {};
|