@liquiditytech/rapidx-cli 1.0.30 → 1.0.32
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/cli/commands/account.js +15 -12
- package/dist/cli/commands/algo.js +3 -2
- package/dist/cli/commands/index.js +6 -6
- package/dist/cli/commands/order.js +2 -2
- package/dist/cli/commands/position.js +3 -1
- package/dist/cli/help.js +1 -1
- package/dist/core/client/capability-executor.js +109 -32
- package/dist/core/client/rapid-x-client.js +6 -32
- package/dist/core/contracts/capabilities.js +18 -10
- package/dist/core/contracts/compatibility.js +1 -1
- package/dist/core/contracts/input-schema.js +39 -13
- package/dist/core/safety/policy.js +9 -5
- package/dist/core/self-check/live-read-only-probes.js +4 -4
- package/dist/core/self-check/live-trading-verification-probes.js +3 -3
- package/dist/core/trading/preview-preflight.js +3 -3
- package/dist/core/trading/preview.js +2 -2
- package/dist/core/trading/trading-verification.js +8 -8
- package/dist/core/version.js +1 -1
- package/dist/mcp/tool-runner.js +2 -2
- package/package.json +1 -1
- package/packages/distribution/docs/cli.md +11 -11
- package/packages/distribution/docs/mcp.md +4 -4
- package/packages/distribution/docs/quickstart.md +5 -5
- package/packages/distribution/docs/self-check.md +1 -1
- package/packages/distribution/docs/tools.md +16 -14
- package/packages/distribution/docs/trading-verification.md +1 -1
- package/packages/distribution/manifests/offline-manifest.json +4 -4
- package/packages/distribution/registry/rapidx.mcp.json +1 -1
|
@@ -2,33 +2,36 @@ import { executeRapidXCapability, findCapabilityById, normalizeUnknownError, pub
|
|
|
2
2
|
import { writeCliAudit } from "../audit.js";
|
|
3
3
|
import { fail, ok } from "../envelope.js";
|
|
4
4
|
import { enforceCliPreviewGate } from "./trade-gate.js";
|
|
5
|
-
const
|
|
6
|
-
overview: "
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
const PORTFOLIO_CAPABILITY_BY_ACTION = {
|
|
6
|
+
overview: "portfolio.overview",
|
|
7
|
+
assets: "portfolio.assets",
|
|
8
|
+
statement: "portfolio.statement",
|
|
9
|
+
"user-fee-rate": "portfolio.user-fee-rate",
|
|
10
|
+
"position-bracket": "portfolio.position-bracket",
|
|
11
|
+
"set-position-mode": "portfolio.set-position-mode"
|
|
9
12
|
};
|
|
10
|
-
export async function
|
|
11
|
-
const capabilityId =
|
|
13
|
+
export async function runPortfolioCommand(action, input) {
|
|
14
|
+
const capabilityId = PORTFOLIO_CAPABILITY_BY_ACTION[action];
|
|
12
15
|
if (!capabilityId) {
|
|
13
|
-
return fail("RCLI12001", `Unknown
|
|
16
|
+
return fail("RCLI12001", `Unknown portfolio command: ${action}`, "FAIL", `rapidx portfolio ${action}`);
|
|
14
17
|
}
|
|
15
18
|
const capability = findCapabilityById(capabilityId);
|
|
16
19
|
if (!capability) {
|
|
17
|
-
return fail("RCLI30002", `Missing capability: ${capabilityId}`, "FAIL", `rapidx
|
|
20
|
+
return fail("RCLI30002", `Missing capability: ${capabilityId}`, "FAIL", `rapidx portfolio ${action}`);
|
|
18
21
|
}
|
|
19
|
-
const blocked = enforceCliPreviewGate(capability, input, `rapidx
|
|
22
|
+
const blocked = enforceCliPreviewGate(capability, input, `rapidx portfolio ${action}`);
|
|
20
23
|
if (blocked) {
|
|
21
24
|
return blocked;
|
|
22
25
|
}
|
|
23
26
|
try {
|
|
24
27
|
const data = await executeRapidXCapability(capabilityId, input);
|
|
25
28
|
const auditId = capability.operationType === "TRADE_WRITE"
|
|
26
|
-
? writeCliAudit("trade-write", "PASS", { command: `rapidx
|
|
29
|
+
? writeCliAudit("trade-write", "PASS", { command: `rapidx portfolio ${action}`, capabilityId })
|
|
27
30
|
: undefined;
|
|
28
|
-
return ok(data, `rapidx
|
|
31
|
+
return ok(data, `rapidx portfolio ${action}`, "PASS", "real_tool_call", auditId);
|
|
29
32
|
}
|
|
30
33
|
catch (error) {
|
|
31
34
|
const productError = normalizeUnknownError(error, "RCLI01001");
|
|
32
|
-
return fail(productError.code.replace(/^RCORE/, "RCLI"), productError.message, productError.status, `rapidx
|
|
35
|
+
return fail(productError.code.replace(/^RCORE/, "RCLI"), productError.message, productError.status, `rapidx portfolio ${action}`, publicErrorDetails(productError));
|
|
33
36
|
}
|
|
34
37
|
}
|
|
@@ -4,9 +4,10 @@ import { fail, ok } from "../envelope.js";
|
|
|
4
4
|
import { enforceCliPreviewGate } from "./trade-gate.js";
|
|
5
5
|
const ALGO_CAPABILITY_BY_ACTION = {
|
|
6
6
|
place: "algo.place",
|
|
7
|
-
|
|
7
|
+
replace: "algo.replace",
|
|
8
8
|
cancel: "algo.cancel",
|
|
9
|
-
|
|
9
|
+
"open-orders": "algo.open-orders",
|
|
10
|
+
query: "algo.query"
|
|
10
11
|
};
|
|
11
12
|
export async function runAlgoCommand(action, input) {
|
|
12
13
|
const capabilityId = ALGO_CAPABILITY_BY_ACTION[action];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { checkInvocationMode } from "../invocation-checker.js";
|
|
2
2
|
import { fail, ok } from "../envelope.js";
|
|
3
|
-
import {
|
|
3
|
+
import { runPortfolioCommand } from "./account.js";
|
|
4
4
|
import { runAlgoCommand } from "./algo.js";
|
|
5
5
|
import { runAuthCheck } from "./auth.js";
|
|
6
6
|
import { runConfigCommand } from "./config.js";
|
|
@@ -54,20 +54,20 @@ export async function dispatchCli(parsed) {
|
|
|
54
54
|
if (domain === "market") {
|
|
55
55
|
return runMarketCommand(action ?? "get-ticker", parsed.input);
|
|
56
56
|
}
|
|
57
|
-
if (domain === "
|
|
58
|
-
return
|
|
57
|
+
if (domain === "portfolio") {
|
|
58
|
+
return runPortfolioCommand(action ?? "overview", parsed.input);
|
|
59
59
|
}
|
|
60
60
|
if (domain === "order") {
|
|
61
|
-
return runOrderCommand(action ?? "
|
|
61
|
+
return runOrderCommand(action ?? "open-orders", parsed.input);
|
|
62
62
|
}
|
|
63
63
|
if (domain === "trade") {
|
|
64
64
|
return runTradeCommand(action ?? "preview", parsed.input);
|
|
65
65
|
}
|
|
66
66
|
if (domain === "position") {
|
|
67
|
-
return runPositionCommand(action ?? "
|
|
67
|
+
return runPositionCommand(action ?? "query", parsed.input);
|
|
68
68
|
}
|
|
69
69
|
if (domain === "algo") {
|
|
70
|
-
return runAlgoCommand(subAction ?? action ?? "
|
|
70
|
+
return runAlgoCommand(subAction ?? action ?? "open-orders", parsed.input);
|
|
71
71
|
}
|
|
72
72
|
return fail("RCLI12001", `Unknown command: ${parsed.command}`);
|
|
73
73
|
}
|
|
@@ -73,8 +73,8 @@ export async function runOrderCommand(action, input) {
|
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
75
|
function previewTargetForAction(action) {
|
|
76
|
-
if (action === "
|
|
77
|
-
return "order.
|
|
76
|
+
if (action === "replace-preview") {
|
|
77
|
+
return "order.replace";
|
|
78
78
|
}
|
|
79
79
|
if (action === "cancel-preview") {
|
|
80
80
|
return "order.cancel";
|
|
@@ -3,9 +3,11 @@ import { writeCliAudit } from "../audit.js";
|
|
|
3
3
|
import { fail, ok } from "../envelope.js";
|
|
4
4
|
import { enforceCliPreviewGate } from "./trade-gate.js";
|
|
5
5
|
const POSITION_CAPABILITY_BY_ACTION = {
|
|
6
|
-
|
|
6
|
+
query: "position.query",
|
|
7
7
|
history: "position.history",
|
|
8
|
+
"get-leverage": "position.get-leverage",
|
|
8
9
|
close: "position.close",
|
|
10
|
+
"close-all": "position.close-all",
|
|
9
11
|
"set-leverage": "position.set-leverage"
|
|
10
12
|
};
|
|
11
13
|
export async function runPositionCommand(action, input) {
|
package/dist/cli/help.js
CHANGED
|
@@ -18,7 +18,7 @@ export function formatCliHelp() {
|
|
|
18
18
|
"",
|
|
19
19
|
"Domains:",
|
|
20
20
|
" schema, doctor, auth, config, update, self-check, invocation",
|
|
21
|
-
" market,
|
|
21
|
+
" market, portfolio, order, trade, position, algo",
|
|
22
22
|
"",
|
|
23
23
|
"Use --input for structured JSON. Named options such as --symbol and --depth are also accepted for simple inputs."
|
|
24
24
|
].join("\n");
|
|
@@ -19,50 +19,65 @@ export async function executeRapidXCapability(capabilityId, input = {}, options
|
|
|
19
19
|
}
|
|
20
20
|
const client = options.client ?? new RapidXClient();
|
|
21
21
|
switch (capabilityId) {
|
|
22
|
-
case "
|
|
22
|
+
case "portfolio.overview":
|
|
23
23
|
return client.get("/api/v1/trading/account");
|
|
24
|
-
case "
|
|
25
|
-
return
|
|
26
|
-
case "
|
|
24
|
+
case "portfolio.assets":
|
|
25
|
+
return client.get("/api/v1/trading/portfolio/assets", optionalParams(input, ["exchangeType", "page", "pageSize"]));
|
|
26
|
+
case "portfolio.statement":
|
|
27
|
+
return client.get("/api/v1/trading/statement", statementParams(input));
|
|
28
|
+
case "portfolio.user-fee-rate":
|
|
29
|
+
return client.get("/api/v1/trading/userFeeRate");
|
|
30
|
+
case "portfolio.position-bracket":
|
|
31
|
+
return client.get("/api/v1/trading/positionBracket", symbolQueryParams(input));
|
|
32
|
+
case "portfolio.set-position-mode":
|
|
27
33
|
return client.post("/api/v1/trading/account", {
|
|
28
34
|
positionMode: String(input.mode),
|
|
29
35
|
exchangeType: String(input.exchange)
|
|
30
36
|
});
|
|
31
37
|
case "order.place":
|
|
32
38
|
return client.post("/api/v1/trading/order", orderPlaceBody(input));
|
|
33
|
-
case "order.
|
|
39
|
+
case "order.replace":
|
|
34
40
|
return client.put("/api/v1/trading/order", orderAmendBody(input));
|
|
35
41
|
case "order.cancel":
|
|
36
42
|
return executeOrderCancelCapability(client, input);
|
|
37
|
-
case "order.
|
|
43
|
+
case "order.cancel-all":
|
|
44
|
+
return client.delete("/api/v1/trading/cancelAll", cancelAllOrdersBody(input));
|
|
45
|
+
case "order.query":
|
|
38
46
|
return client.get("/api/v1/trading/order", orderReadParams(input));
|
|
39
|
-
case "order.
|
|
40
|
-
return client.get("/api/v1/trading/orders",
|
|
47
|
+
case "order.open-orders":
|
|
48
|
+
return client.get("/api/v1/trading/orders", orderListParams(input, "1000"));
|
|
41
49
|
case "order.history":
|
|
42
|
-
return client.get("/api/v1/trading/history/orders",
|
|
43
|
-
case "
|
|
50
|
+
return client.get("/api/v1/trading/history/orders", orderListParams(input, "100"));
|
|
51
|
+
case "order.executions":
|
|
52
|
+
return client.get("/api/v1/trading/executions", executionParams(input));
|
|
53
|
+
case "position.query":
|
|
44
54
|
return executePositionListCapability(client, input);
|
|
45
55
|
case "position.history":
|
|
46
56
|
return client.get("/api/v1/trading/history/position", {
|
|
47
57
|
pageSize: stringValue(input.pageSize, "100"),
|
|
48
58
|
...positionHistoryParams(input)
|
|
49
59
|
});
|
|
60
|
+
case "position.get-leverage":
|
|
61
|
+
return client.get("/api/v1/trading/perp/leverage", symbolQueryParams(input));
|
|
50
62
|
case "position.close":
|
|
51
63
|
return executePositionCloseCapability(client, input);
|
|
64
|
+
case "position.close-all":
|
|
65
|
+
return client.delete("/api/v1/trading/positions", closeAllPositionsBody(input));
|
|
52
66
|
case "position.set-leverage":
|
|
53
67
|
return client.post("/api/v1/trading/position/leverage", compactObject({
|
|
54
68
|
sym: String(input.symbol),
|
|
55
|
-
leverage: String(input.leverage)
|
|
56
|
-
positionSide: input.positionSide
|
|
69
|
+
leverage: String(input.leverage)
|
|
57
70
|
}));
|
|
58
71
|
case "algo.place":
|
|
59
72
|
return client.post("/api/v1/algo/order", algoPlaceBody(input));
|
|
60
|
-
case "algo.
|
|
73
|
+
case "algo.replace":
|
|
61
74
|
return client.put("/api/v1/algo/order", algoAmendBody(input));
|
|
62
75
|
case "algo.cancel":
|
|
63
76
|
return client.delete("/api/v1/algo/order", optionalParams(input, ["algoOrderId", "clientOrderId"]));
|
|
64
|
-
case "algo.
|
|
77
|
+
case "algo.open-orders":
|
|
65
78
|
return client.get("/api/v1/algo/openOrders", algoListParams(input));
|
|
79
|
+
case "algo.query":
|
|
80
|
+
return client.get("/api/v1/algo/order", optionalParams(input, ["algoOrderId", "clientOrderId", "attachedOrderId"]));
|
|
66
81
|
default:
|
|
67
82
|
throw new ProductError({
|
|
68
83
|
code: "RCORE30002",
|
|
@@ -133,14 +148,6 @@ async function executeMarketCapability(capabilityId, input, fetchFn) {
|
|
|
133
148
|
throw new ProductError({ code: "RCORE30002", status: "FAIL", message: `Unknown market capability: ${capabilityId}` });
|
|
134
149
|
}
|
|
135
150
|
}
|
|
136
|
-
function executeAccountBalanceCapability(client, input) {
|
|
137
|
-
const mode = String(input.mode ?? "portfolio").toLowerCase();
|
|
138
|
-
const params = optionalParams(input, ["currency"]);
|
|
139
|
-
if (mode === "account") {
|
|
140
|
-
return client.get("/api/v1/account/balance", params);
|
|
141
|
-
}
|
|
142
|
-
return client.get("/api/v1/trading/portfolio/assets", params);
|
|
143
|
-
}
|
|
144
151
|
async function executePositionListCapability(client, input) {
|
|
145
152
|
const params = {};
|
|
146
153
|
if (input.symbol !== undefined && input.symbol !== null && input.symbol !== "") {
|
|
@@ -160,7 +167,7 @@ async function executePositionCloseCapability(client, input) {
|
|
|
160
167
|
positionSide: input.positionSide,
|
|
161
168
|
maxNotional: input.maxNotional
|
|
162
169
|
}),
|
|
163
|
-
readbackNote: "position.close uses RapidX close-position API; order.
|
|
170
|
+
readbackNote: "position.close uses RapidX close-position API; order.query reduceOnly may not reflect this close-position request. Verify final exposure with position.query.",
|
|
164
171
|
response
|
|
165
172
|
};
|
|
166
173
|
}
|
|
@@ -173,8 +180,8 @@ async function executeOrderCancelCapability(client, input) {
|
|
|
173
180
|
terminalStateConfirmed,
|
|
174
181
|
...compactObject({ lastObservedOrderState }),
|
|
175
182
|
recommendedAction: terminalStateConfirmed
|
|
176
|
-
? "verify final status with order/
|
|
177
|
-
: "poll order/
|
|
183
|
+
? "verify final status with order/query or order/open-orders when needed"
|
|
184
|
+
: "poll order/query until CANCELED, REJECTED, EXPIRED, or timeout",
|
|
178
185
|
response
|
|
179
186
|
};
|
|
180
187
|
}
|
|
@@ -286,9 +293,59 @@ function orderCancelBody(input) {
|
|
|
286
293
|
assertValidOrderId(input.orderId);
|
|
287
294
|
return optionalParams(input, ["orderId", "clientOrderId"]);
|
|
288
295
|
}
|
|
296
|
+
function cancelAllOrdersBody(input) {
|
|
297
|
+
const body = optionalParams(input, ["exchangeType"]);
|
|
298
|
+
if (input.symbol !== undefined && input.symbol !== null && input.symbol !== "") {
|
|
299
|
+
body.sym = String(input.symbol);
|
|
300
|
+
}
|
|
301
|
+
return body;
|
|
302
|
+
}
|
|
289
303
|
function orderReadParams(input) {
|
|
290
304
|
assertOrderLookupReference(input);
|
|
291
|
-
return
|
|
305
|
+
return {
|
|
306
|
+
...optionalParams(input, ["orderId", "clientOrderId"]),
|
|
307
|
+
...symbolQueryParams(input)
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
function orderListParams(input, defaultPageSize) {
|
|
311
|
+
return {
|
|
312
|
+
pageSize: stringValue(input.pageSize, defaultPageSize),
|
|
313
|
+
...mappedOptionalParams(input, [
|
|
314
|
+
["symbol", "sym"],
|
|
315
|
+
["exchange", "exchange"],
|
|
316
|
+
["businessType", "businessType"],
|
|
317
|
+
["startTime", "begin"],
|
|
318
|
+
["endTime", "end"],
|
|
319
|
+
["page", "page"],
|
|
320
|
+
["filterExecuted", "filterExecuted"]
|
|
321
|
+
])
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
function executionParams(input) {
|
|
325
|
+
return mappedOptionalParams(input, [
|
|
326
|
+
["orderId", "orderId"],
|
|
327
|
+
["symbol", "sym"],
|
|
328
|
+
["exchange", "exchange"],
|
|
329
|
+
["businessType", "businessType"],
|
|
330
|
+
["startTime", "begin"],
|
|
331
|
+
["endTime", "end"],
|
|
332
|
+
["limit", "limit"]
|
|
333
|
+
]);
|
|
334
|
+
}
|
|
335
|
+
function statementParams(input) {
|
|
336
|
+
return mappedOptionalParams(input, [
|
|
337
|
+
["coin", "coin"],
|
|
338
|
+
["symbol", "sym"],
|
|
339
|
+
["statementType", "statementType"],
|
|
340
|
+
["exchange", "exchange"],
|
|
341
|
+
["startTime", "startTime"],
|
|
342
|
+
["endTime", "endTime"],
|
|
343
|
+
["page", "page"],
|
|
344
|
+
["pageSize", "pageSize"]
|
|
345
|
+
]);
|
|
346
|
+
}
|
|
347
|
+
function symbolQueryParams(input) {
|
|
348
|
+
return mappedOptionalParams(input, [["symbol", "sym"]]);
|
|
292
349
|
}
|
|
293
350
|
function positionCloseBody(input) {
|
|
294
351
|
const body = {
|
|
@@ -299,6 +356,14 @@ function positionCloseBody(input) {
|
|
|
299
356
|
}
|
|
300
357
|
return body;
|
|
301
358
|
}
|
|
359
|
+
function closeAllPositionsBody(input) {
|
|
360
|
+
return compactObject({
|
|
361
|
+
symList: input.symbolList,
|
|
362
|
+
positionSide: input.positionSide,
|
|
363
|
+
closeAllPos: input.closeAllPositions === undefined ? undefined : input.closeAllPositions === true ? "true" : "false",
|
|
364
|
+
exchangeType: input.exchangeType
|
|
365
|
+
});
|
|
366
|
+
}
|
|
302
367
|
function algoPlaceBody(input) {
|
|
303
368
|
const body = {
|
|
304
369
|
...orderPlaceBody(input),
|
|
@@ -329,14 +394,21 @@ function algoAmendBody(input) {
|
|
|
329
394
|
return body;
|
|
330
395
|
}
|
|
331
396
|
function algoListParams(input) {
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
397
|
+
return mappedOptionalParams(input, [
|
|
398
|
+
["symbol", "sym"],
|
|
399
|
+
["exchange", "exchange"],
|
|
400
|
+
["businessType", "businessType"],
|
|
401
|
+
["startTime", "begin"],
|
|
402
|
+
["endTime", "end"],
|
|
403
|
+
["page", "page"],
|
|
404
|
+
["pageSize", "pageSize"]
|
|
405
|
+
]);
|
|
337
406
|
}
|
|
338
407
|
function positionHistoryParams(input) {
|
|
339
|
-
const params =
|
|
408
|
+
const params = mappedOptionalParams(input, [
|
|
409
|
+
["startTime", "begin"],
|
|
410
|
+
["endTime", "end"]
|
|
411
|
+
]);
|
|
340
412
|
if (input.symbol !== undefined && input.symbol !== null && input.symbol !== "") {
|
|
341
413
|
params.sym = String(input.symbol);
|
|
342
414
|
}
|
|
@@ -469,6 +541,11 @@ function appendMappedOptionalParams(target, input, mappings) {
|
|
|
469
541
|
}
|
|
470
542
|
}
|
|
471
543
|
}
|
|
544
|
+
function mappedOptionalParams(input, mappings) {
|
|
545
|
+
const result = {};
|
|
546
|
+
appendMappedOptionalParams(result, input, mappings);
|
|
547
|
+
return result;
|
|
548
|
+
}
|
|
472
549
|
function omitKeys(input, keys) {
|
|
473
550
|
const blocked = new Set(keys);
|
|
474
551
|
return Object.fromEntries(Object.entries(input).filter(([key]) => !blocked.has(key)));
|
|
@@ -65,12 +65,11 @@ export class RapidXClient {
|
|
|
65
65
|
await delay(this.readOnlyRetryDelayMs * (2 ** (attempt - 1)));
|
|
66
66
|
continue;
|
|
67
67
|
}
|
|
68
|
-
const hint = upstreamHttpErrorHint(path, response.status, text);
|
|
69
68
|
throw new ProductError({
|
|
70
|
-
code: upstreamHttpErrorCode(
|
|
71
|
-
status: upstreamHttpErrorStatus(
|
|
72
|
-
message:
|
|
73
|
-
details: { upstreamStatus: response.status, status: response.status, body: text.slice(0, 500), attempts: attempt
|
|
69
|
+
code: upstreamHttpErrorCode(response.status),
|
|
70
|
+
status: upstreamHttpErrorStatus(response.status),
|
|
71
|
+
message: `RapidX upstream error ${response.status}`,
|
|
72
|
+
details: { upstreamStatus: response.status, status: response.status, body: text.slice(0, 500), attempts: attempt }
|
|
74
73
|
});
|
|
75
74
|
}
|
|
76
75
|
if (!text) {
|
|
@@ -111,16 +110,7 @@ function resolveBaseUrl(explicitBaseUrl) {
|
|
|
111
110
|
function firstNonEmpty(...values) {
|
|
112
111
|
return values.find((value) => value !== undefined && value.length > 0);
|
|
113
112
|
}
|
|
114
|
-
function
|
|
115
|
-
if (isAccountBalanceScopeError(path, status, body)) {
|
|
116
|
-
return "account balance mode=account requires account-level credentials; portfolio keys should use mode=portfolio.";
|
|
117
|
-
}
|
|
118
|
-
return undefined;
|
|
119
|
-
}
|
|
120
|
-
function upstreamHttpErrorCode(path, status, body) {
|
|
121
|
-
if (isAccountBalanceScopeError(path, status, body)) {
|
|
122
|
-
return CORE_ERRORS.PERMISSION_SCOPE_ERROR;
|
|
123
|
-
}
|
|
113
|
+
function upstreamHttpErrorCode(status) {
|
|
124
114
|
if (status === 404) {
|
|
125
115
|
return CORE_ERRORS.NOT_FOUND;
|
|
126
116
|
}
|
|
@@ -132,28 +122,12 @@ function upstreamHttpErrorCode(path, status, body) {
|
|
|
132
122
|
}
|
|
133
123
|
return CORE_ERRORS.INVALID_CREDENTIAL;
|
|
134
124
|
}
|
|
135
|
-
function upstreamHttpErrorStatus(
|
|
136
|
-
if (isAccountBalanceScopeError(path, status, body)) {
|
|
137
|
-
return "PERMISSION_SCOPE_ERROR";
|
|
138
|
-
}
|
|
125
|
+
function upstreamHttpErrorStatus(status) {
|
|
139
126
|
if (status === 404) {
|
|
140
127
|
return "NOT_FOUND";
|
|
141
128
|
}
|
|
142
129
|
return "FAIL";
|
|
143
130
|
}
|
|
144
|
-
function isAccountBalanceScopeError(path, status, body) {
|
|
145
|
-
if (path !== "/api/v1/account/balance" || status < 400) {
|
|
146
|
-
return false;
|
|
147
|
-
}
|
|
148
|
-
if (status >= 500) {
|
|
149
|
-
return true;
|
|
150
|
-
}
|
|
151
|
-
const lowerBody = body.toLowerCase();
|
|
152
|
-
return lowerBody.includes("account-level")
|
|
153
|
-
|| lowerBody.includes("permission scope")
|
|
154
|
-
|| lowerBody.includes("credential scope")
|
|
155
|
-
|| (lowerBody.includes("portfolio") && lowerBody.includes("account"));
|
|
156
|
-
}
|
|
157
131
|
function delay(ms) {
|
|
158
132
|
if (ms <= 0) {
|
|
159
133
|
return Promise.resolve();
|
|
@@ -17,28 +17,36 @@ export const CAPABILITIES = [
|
|
|
17
17
|
{ capabilityId: "market.mark-price", cliCommand: "rapidx market get-mark-price", mcpTool: "rapidx/market/get-mark-price", operationType: "READ", riskLevel: "read", inputSchema: "SymbolInput", outputSchema: "MarkPrice", previewRequired: false },
|
|
18
18
|
{ capabilityId: "market.symbol-info", cliCommand: "rapidx market get-symbol-info", mcpTool: "rapidx/market/get-symbol-info", operationType: "READ", riskLevel: "read", inputSchema: "SymbolInput", outputSchema: "SymbolInfo", previewRequired: false },
|
|
19
19
|
{ capabilityId: "market.open-interest", cliCommand: "rapidx market get-open-interest", mcpTool: "rapidx/market/get-open-interest", operationType: "READ", riskLevel: "read", inputSchema: "SymbolInput", outputSchema: "OpenInterest", previewRequired: false },
|
|
20
|
-
{ capabilityId: "
|
|
21
|
-
{ capabilityId: "
|
|
22
|
-
{ capabilityId: "
|
|
20
|
+
{ capabilityId: "portfolio.overview", cliCommand: "rapidx portfolio overview", mcpTool: "rapidx/portfolio/overview", operationType: "TRADE_READ", riskLevel: "trade-read", inputSchema: "EmptyInput", outputSchema: "PortfolioOverview", previewRequired: false },
|
|
21
|
+
{ capabilityId: "portfolio.assets", cliCommand: "rapidx portfolio assets", mcpTool: "rapidx/portfolio/assets", operationType: "TRADE_READ", riskLevel: "trade-read", inputSchema: "PortfolioAssetsInput", outputSchema: "PortfolioAssets", previewRequired: false },
|
|
22
|
+
{ capabilityId: "portfolio.statement", cliCommand: "rapidx portfolio statement", mcpTool: "rapidx/portfolio/statement", operationType: "TRADE_READ", riskLevel: "trade-read", inputSchema: "StatementInput", outputSchema: "StatementResult", previewRequired: false },
|
|
23
|
+
{ capabilityId: "portfolio.user-fee-rate", cliCommand: "rapidx portfolio user-fee-rate", mcpTool: "rapidx/portfolio/user-fee-rate", operationType: "TRADE_READ", riskLevel: "trade-read", inputSchema: "EmptyInput", outputSchema: "UserFeeRate", previewRequired: false },
|
|
24
|
+
{ capabilityId: "portfolio.position-bracket", cliCommand: "rapidx portfolio position-bracket", mcpTool: "rapidx/portfolio/position-bracket", operationType: "TRADE_READ", riskLevel: "trade-read", inputSchema: "PositionBracketInput", outputSchema: "PositionBracket", previewRequired: false },
|
|
25
|
+
{ capabilityId: "portfolio.set-position-mode", cliCommand: "rapidx portfolio set-position-mode", mcpTool: "rapidx/portfolio/set-position-mode", operationType: "TRADE_WRITE", riskLevel: "critical-trade-write", inputSchema: "SetPositionModeInput", outputSchema: "SetPositionModeResult", previewRequired: true },
|
|
23
26
|
{ capabilityId: "trade.preview", cliCommand: "rapidx trade preview", mcpTool: "rapidx/trade/preview", operationType: "TRADE_WRITE", riskLevel: "trade-write", inputSchema: "TradePreviewInput", outputSchema: "TradePreviewResult", previewRequired: false },
|
|
24
27
|
{ capabilityId: "order.preview", cliCommand: "rapidx order preview", mcpTool: "rapidx/order/preview", operationType: "TRADE_WRITE", riskLevel: "trade-write", inputSchema: "PreviewOrderInput", outputSchema: "PreviewOrderResult", previewRequired: false },
|
|
25
28
|
{ capabilityId: "order.place-preview", cliCommand: "rapidx order place-preview", mcpTool: "rapidx/order/place-preview", operationType: "TRADE_WRITE", riskLevel: "trade-write", inputSchema: "PreviewOrderInput", outputSchema: "PreviewOrderResult", previewRequired: false },
|
|
26
|
-
{ capabilityId: "order.
|
|
29
|
+
{ capabilityId: "order.replace-preview", cliCommand: "rapidx order replace-preview", mcpTool: "rapidx/order/replace-preview", operationType: "TRADE_WRITE", riskLevel: "trade-write", inputSchema: "ReplaceOrderPreviewInput", outputSchema: "TradePreviewResult", previewRequired: false },
|
|
27
30
|
{ capabilityId: "order.cancel-preview", cliCommand: "rapidx order cancel-preview", mcpTool: "rapidx/order/cancel-preview", operationType: "TRADE_WRITE", riskLevel: "trade-write", inputSchema: "CancelOrderPreviewInput", outputSchema: "TradePreviewResult", previewRequired: false },
|
|
28
31
|
{ capabilityId: "order.place", cliCommand: "rapidx order place", mcpTool: "rapidx/order/place", operationType: "TRADE_WRITE", riskLevel: "trade-write", inputSchema: "PlaceOrderInput", outputSchema: "OrderStatusResult", previewRequired: true },
|
|
29
|
-
{ capabilityId: "order.
|
|
32
|
+
{ capabilityId: "order.replace", cliCommand: "rapidx order replace", mcpTool: "rapidx/order/replace", operationType: "TRADE_WRITE", riskLevel: "trade-write", inputSchema: "ReplaceOrderInput", outputSchema: "OrderStatusResult", previewRequired: true },
|
|
30
33
|
{ capabilityId: "order.cancel", cliCommand: "rapidx order cancel", mcpTool: "rapidx/order/cancel", operationType: "TRADE_WRITE", riskLevel: "trade-write", inputSchema: "CancelOrderInput", outputSchema: "OrderStatusResult", previewRequired: true },
|
|
31
|
-
{ capabilityId: "order.
|
|
32
|
-
{ capabilityId: "order.
|
|
34
|
+
{ capabilityId: "order.cancel-all", cliCommand: "rapidx order cancel-all", mcpTool: "rapidx/order/cancel-all", operationType: "TRADE_WRITE", riskLevel: "critical-trade-write", inputSchema: "CancelAllOrdersInput", outputSchema: "CancelAllOrdersResult", previewRequired: true },
|
|
35
|
+
{ capabilityId: "order.query", cliCommand: "rapidx order query", mcpTool: "rapidx/order/query", operationType: "TRADE_READ", riskLevel: "trade-read", inputSchema: "OrderLookupInput", outputSchema: "OrderStatusResult", previewRequired: false },
|
|
36
|
+
{ capabilityId: "order.open-orders", cliCommand: "rapidx order open-orders", mcpTool: "rapidx/order/open-orders", operationType: "TRADE_READ", riskLevel: "trade-read", inputSchema: "OrderListInput", outputSchema: "OrderList", previewRequired: false },
|
|
33
37
|
{ capabilityId: "order.history", cliCommand: "rapidx order history", mcpTool: "rapidx/order/history", operationType: "TRADE_READ", riskLevel: "trade-read", inputSchema: "OrderHistoryInput", outputSchema: "OrderHistory", previewRequired: false },
|
|
34
|
-
{ capabilityId: "
|
|
38
|
+
{ capabilityId: "order.executions", cliCommand: "rapidx order executions", mcpTool: "rapidx/order/executions", operationType: "TRADE_READ", riskLevel: "trade-read", inputSchema: "ExecutionListInput", outputSchema: "ExecutionList", previewRequired: false },
|
|
39
|
+
{ capabilityId: "position.query", cliCommand: "rapidx position query", mcpTool: "rapidx/position/query", operationType: "TRADE_READ", riskLevel: "trade-read", inputSchema: "PositionListInput", outputSchema: "PositionList", previewRequired: false },
|
|
35
40
|
{ capabilityId: "position.history", cliCommand: "rapidx position history", mcpTool: "rapidx/position/history", operationType: "TRADE_READ", riskLevel: "trade-read", inputSchema: "PositionHistoryInput", outputSchema: "PositionHistory", previewRequired: false },
|
|
41
|
+
{ capabilityId: "position.get-leverage", cliCommand: "rapidx position get-leverage", mcpTool: "rapidx/position/get-leverage", operationType: "TRADE_READ", riskLevel: "trade-read", inputSchema: "SymbolInput", outputSchema: "PositionLeverage", previewRequired: false },
|
|
36
42
|
{ capabilityId: "position.close", cliCommand: "rapidx position close", mcpTool: "rapidx/position/close", operationType: "TRADE_WRITE", riskLevel: "critical-trade-write", inputSchema: "ClosePositionInput", outputSchema: "ClosePositionResult", previewRequired: true },
|
|
43
|
+
{ capabilityId: "position.close-all", cliCommand: "rapidx position close-all", mcpTool: "rapidx/position/close-all", operationType: "TRADE_WRITE", riskLevel: "critical-trade-write", inputSchema: "CloseAllPositionsInput", outputSchema: "CloseAllPositionsResult", previewRequired: true },
|
|
37
44
|
{ capabilityId: "position.set-leverage", cliCommand: "rapidx position set-leverage", mcpTool: "rapidx/position/set-leverage", operationType: "TRADE_WRITE", riskLevel: "critical-trade-write", inputSchema: "SetLeverageInput", outputSchema: "SetLeverageResult", previewRequired: true },
|
|
38
45
|
{ capabilityId: "algo.place", cliCommand: "rapidx algo place", mcpTool: "rapidx/algo/place", operationType: "TRADE_WRITE", riskLevel: "trade-write", inputSchema: "AlgoPlaceInput", outputSchema: "AlgoOrderStatus", previewRequired: true },
|
|
39
|
-
{ capabilityId: "algo.
|
|
46
|
+
{ capabilityId: "algo.replace", cliCommand: "rapidx algo replace", mcpTool: "rapidx/algo/replace", operationType: "TRADE_WRITE", riskLevel: "trade-write", inputSchema: "AlgoReplaceInput", outputSchema: "AlgoOrderStatus", previewRequired: true },
|
|
40
47
|
{ capabilityId: "algo.cancel", cliCommand: "rapidx algo cancel", mcpTool: "rapidx/algo/cancel", operationType: "TRADE_WRITE", riskLevel: "trade-write", inputSchema: "AlgoCancelInput", outputSchema: "AlgoOrderStatus", previewRequired: true },
|
|
41
|
-
{ capabilityId: "algo.
|
|
48
|
+
{ capabilityId: "algo.open-orders", cliCommand: "rapidx algo open-orders", mcpTool: "rapidx/algo/open-orders", operationType: "TRADE_READ", riskLevel: "trade-read", inputSchema: "AlgoListInput", outputSchema: "AlgoList", previewRequired: false },
|
|
49
|
+
{ capabilityId: "algo.query", cliCommand: "rapidx algo query", mcpTool: "rapidx/algo/query", operationType: "TRADE_READ", riskLevel: "trade-read", inputSchema: "AlgoLookupInput", outputSchema: "AlgoOrderStatus", previewRequired: false },
|
|
42
50
|
{ capabilityId: "trading.verify", cliCommand: "rapidx self-check trade-verify", mcpTool: "rapidx/trading-verification", operationType: "TRADE_WRITE", riskLevel: "critical-trade-write", inputSchema: "TradingVerificationInput", outputSchema: "TradingVerificationReport", previewRequired: false, containsRealOrder: true, requiresExplicitHumanConfirmation: true, confirmationMode: "internal-preview-and-parameter-bound-consent" },
|
|
43
51
|
{ capabilityId: "trading.verify-live", cliCommand: "rapidx trade verify-live", mcpTool: "rapidx/trade/verify-live", operationType: "TRADE_WRITE", riskLevel: "critical-trade-write", inputSchema: "TradingVerificationInput", outputSchema: "TradingVerificationReport", previewRequired: false, containsRealOrder: true, requiresExplicitHumanConfirmation: true, confirmationMode: "internal-preview-and-parameter-bound-consent" },
|
|
44
52
|
{ capabilityId: "invocation.check", cliCommand: "rapidx invocation check", operationType: "DIAGNOSTIC", riskLevel: "read", inputSchema: "InvocationCheckInput", outputSchema: "InvocationCompliance", previewRequired: false }
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { SCHEMA_VERSION } from "./types.js";
|
|
2
2
|
import { RAPIDX_VERSION } from "../version.js";
|
|
3
3
|
export const RAPIDX_SKILLS_DISTRIBUTION = "github";
|
|
4
|
-
export const RAPIDX_SKILLS_VERSION = "1.0.
|
|
4
|
+
export const RAPIDX_SKILLS_VERSION = "1.0.6";
|
|
5
5
|
export const RAPIDX_SKILLS_SCHEMA_VERSION = "1.0.0";
|
|
6
6
|
export function buildCompatibilityReport(input = {}) {
|
|
7
7
|
const checks = [
|
|
@@ -85,13 +85,24 @@ const targetCapabilityIdSchema = {
|
|
|
85
85
|
};
|
|
86
86
|
const orderIdSchema = {
|
|
87
87
|
type: "string",
|
|
88
|
-
description: "RapidX order id returned by order.place, order.
|
|
88
|
+
description: "RapidX order id returned by order.place, order.open-orders, or order.query.",
|
|
89
89
|
examples: ["2173374713391199"]
|
|
90
90
|
};
|
|
91
|
-
const
|
|
91
|
+
const exchangeTypeSchema = { type: "string", description: "RapidX exchange type, for example BINANCE or OKX." };
|
|
92
|
+
const businessTypeSchema = { type: "string", description: "RapidX business type, for example PERP." };
|
|
93
|
+
const pageSchema = { type: "number", description: "1-based page number." };
|
|
94
|
+
const pageSizeSchema = { type: "number", description: "Page size." };
|
|
95
|
+
const startTimeSchema = { type: "string", description: "Start timestamp accepted by the RapidX API." };
|
|
96
|
+
const endTimeSchema = { type: "string", description: "End timestamp accepted by the RapidX API." };
|
|
97
|
+
const coinSchema = { type: "string", description: "Asset coin, for example USDT." };
|
|
98
|
+
const statementTypeSchema = { type: "string", description: "RapidX statement type filter." };
|
|
99
|
+
const filterExecutedSchema = { type: "boolean", description: "Whether to filter executed order history where the endpoint supports it." };
|
|
100
|
+
const closeAllPositionsSchema = { type: "boolean", description: "When true, requests RapidX to close all positions allowed by the provided filters." };
|
|
101
|
+
const symbolListSchema = { type: "string", description: "Comma-separated RapidX symbols for close-all position requests." };
|
|
102
|
+
const closeAllPositionSideSchema = {
|
|
92
103
|
type: "string",
|
|
93
|
-
enum: ["
|
|
94
|
-
description: "
|
|
104
|
+
enum: ["LONG", "SHORT", "NONE"],
|
|
105
|
+
description: "Position side for close-all. Use NONE only when the RapidX close-all endpoint accepts it for one-way mode."
|
|
95
106
|
};
|
|
96
107
|
const positionSideSchema = {
|
|
97
108
|
type: "string",
|
|
@@ -114,8 +125,10 @@ export function inputSchemaForName(name) {
|
|
|
114
125
|
return objectSchema({ symbol: symbolSchema, depth: numberSchema }, ["symbol"]);
|
|
115
126
|
case "KlinesInput":
|
|
116
127
|
return objectSchema({ symbol: symbolSchema, interval: stringSchema, limit: numberSchema }, ["symbol"]);
|
|
117
|
-
case "
|
|
118
|
-
return objectSchema({
|
|
128
|
+
case "PortfolioAssetsInput":
|
|
129
|
+
return objectSchema({ exchangeType: exchangeTypeSchema, page: pageSchema, pageSize: pageSizeSchema });
|
|
130
|
+
case "PositionBracketInput":
|
|
131
|
+
return objectSchema({ symbol: symbolSchema }, ["symbol"]);
|
|
119
132
|
case "OrderLookupInput":
|
|
120
133
|
return {
|
|
121
134
|
...objectSchema({ orderId: orderIdSchema, clientOrderId: clientOrderIdSchema, symbol: symbolSchema }),
|
|
@@ -123,12 +136,16 @@ export function inputSchemaForName(name) {
|
|
|
123
136
|
};
|
|
124
137
|
case "OrderListInput":
|
|
125
138
|
case "OrderHistoryInput":
|
|
126
|
-
return objectSchema({ symbol: symbolSchema, pageSize:
|
|
139
|
+
return objectSchema({ symbol: symbolSchema, exchange: stringSchema, businessType: businessTypeSchema, page: pageSchema, pageSize: pageSizeSchema, startTime: startTimeSchema, endTime: endTimeSchema, filterExecuted: filterExecutedSchema });
|
|
140
|
+
case "ExecutionListInput":
|
|
141
|
+
return objectSchema({ orderId: orderIdSchema, symbol: symbolSchema, exchange: stringSchema, businessType: businessTypeSchema, limit: numberSchema, startTime: startTimeSchema, endTime: endTimeSchema });
|
|
142
|
+
case "StatementInput":
|
|
143
|
+
return objectSchema({ coin: coinSchema, symbol: symbolSchema, statementType: statementTypeSchema, exchange: stringSchema, page: pageSchema, pageSize: pageSizeSchema, startTime: startTimeSchema, endTime: endTimeSchema });
|
|
127
144
|
case "PositionListInput":
|
|
128
145
|
case "AlgoListInput":
|
|
129
|
-
return objectSchema({ symbol: symbolSchema });
|
|
146
|
+
return objectSchema({ symbol: symbolSchema, exchange: stringSchema, businessType: businessTypeSchema, page: pageSchema, pageSize: pageSizeSchema, startTime: startTimeSchema, endTime: endTimeSchema });
|
|
130
147
|
case "PositionHistoryInput":
|
|
131
|
-
return objectSchema({ symbol: symbolSchema, pageSize:
|
|
148
|
+
return objectSchema({ symbol: symbolSchema, pageSize: pageSizeSchema, startTime: startTimeSchema, endTime: endTimeSchema });
|
|
132
149
|
case "TradePreviewInput":
|
|
133
150
|
return objectSchema({
|
|
134
151
|
targetCapabilityId: targetCapabilityIdSchema,
|
|
@@ -184,7 +201,7 @@ export function inputSchemaForName(name) {
|
|
|
184
201
|
]),
|
|
185
202
|
oneOf: [{ required: ["quantity"] }, { required: ["amount"] }]
|
|
186
203
|
};
|
|
187
|
-
case "
|
|
204
|
+
case "ReplaceOrderPreviewInput":
|
|
188
205
|
return {
|
|
189
206
|
...objectSchema({ orderId: orderIdSchema, clientOrderId: clientOrderIdSchema, price: priceSchema, quantity: quantitySchema, ...automationProperties(), ...compatibilityProperties() }),
|
|
190
207
|
allOf: [
|
|
@@ -197,7 +214,7 @@ export function inputSchemaForName(name) {
|
|
|
197
214
|
...objectSchema({ orderId: orderIdSchema, clientOrderId: clientOrderIdSchema, ...automationProperties(), ...compatibilityProperties() }),
|
|
198
215
|
anyOf: [{ required: ["orderId"] }, { required: ["clientOrderId"] }]
|
|
199
216
|
};
|
|
200
|
-
case "
|
|
217
|
+
case "ReplaceOrderInput":
|
|
201
218
|
return {
|
|
202
219
|
...objectSchema({ orderId: orderIdSchema, clientOrderId: clientOrderIdSchema, price: priceSchema, quantity: quantitySchema, previewId: previewIdSchema, continueConsentId: continueConsentIdSchema }, ["previewId", "continueConsentId"]),
|
|
203
220
|
allOf: [
|
|
@@ -210,10 +227,14 @@ export function inputSchemaForName(name) {
|
|
|
210
227
|
...objectSchema({ orderId: orderIdSchema, clientOrderId: clientOrderIdSchema, previewId: previewIdSchema, continueConsentId: continueConsentIdSchema }, ["previewId", "continueConsentId"]),
|
|
211
228
|
anyOf: [{ required: ["orderId"] }, { required: ["clientOrderId"] }]
|
|
212
229
|
};
|
|
230
|
+
case "CancelAllOrdersInput":
|
|
231
|
+
return objectSchema({ exchangeType: exchangeTypeSchema, symbol: symbolSchema, previewId: previewIdSchema, continueConsentId: continueConsentIdSchema }, ["previewId", "continueConsentId"]);
|
|
213
232
|
case "ClosePositionInput":
|
|
214
233
|
return objectSchema({ symbol: symbolSchema, positionSide: positionSideSchema, reduceOnly: closePositionReduceOnlySchema, maxNotional: maxNotionalSchema, previewId: previewIdSchema, continueConsentId: continueConsentIdSchema }, ["symbol", "reduceOnly", "maxNotional", "previewId", "continueConsentId"]);
|
|
234
|
+
case "CloseAllPositionsInput":
|
|
235
|
+
return objectSchema({ symbolList: symbolListSchema, positionSide: closeAllPositionSideSchema, closeAllPositions: closeAllPositionsSchema, exchangeType: exchangeTypeSchema, previewId: previewIdSchema, continueConsentId: continueConsentIdSchema }, ["previewId", "continueConsentId"]);
|
|
215
236
|
case "SetLeverageInput":
|
|
216
|
-
return objectSchema({ symbol: symbolSchema, leverage: numberSchema,
|
|
237
|
+
return objectSchema({ symbol: symbolSchema, leverage: numberSchema, previewId: previewIdSchema, continueConsentId: continueConsentIdSchema }, ["symbol", "leverage", "previewId", "continueConsentId"]);
|
|
217
238
|
case "SetPositionModeInput":
|
|
218
239
|
return objectSchema({ mode: { type: "string", enum: ["BOTH", "NET"] }, exchange: stringSchema, previewId: previewIdSchema, continueConsentId: continueConsentIdSchema }, ["mode", "exchange", "previewId", "continueConsentId"]);
|
|
219
240
|
case "AlgoPlaceInput":
|
|
@@ -242,7 +263,7 @@ export function inputSchemaForName(name) {
|
|
|
242
263
|
]),
|
|
243
264
|
anyOf: [{ required: ["quantity"] }, { required: ["amount"] }, { required: ["conditionType"] }]
|
|
244
265
|
};
|
|
245
|
-
case "
|
|
266
|
+
case "AlgoReplaceInput":
|
|
246
267
|
return objectSchema({
|
|
247
268
|
algoOrderId: stringSchema,
|
|
248
269
|
clientOrderId: clientOrderIdSchema,
|
|
@@ -257,6 +278,11 @@ export function inputSchemaForName(name) {
|
|
|
257
278
|
}, ["previewId", "continueConsentId"]);
|
|
258
279
|
case "AlgoCancelInput":
|
|
259
280
|
return objectSchema({ algoOrderId: stringSchema, clientOrderId: clientOrderIdSchema, previewId: previewIdSchema, continueConsentId: continueConsentIdSchema }, ["previewId", "continueConsentId"]);
|
|
281
|
+
case "AlgoLookupInput":
|
|
282
|
+
return {
|
|
283
|
+
...objectSchema({ algoOrderId: stringSchema, clientOrderId: clientOrderIdSchema, attachedOrderId: stringSchema }),
|
|
284
|
+
anyOf: [{ required: ["algoOrderId"] }, { required: ["clientOrderId"] }, { required: ["attachedOrderId"] }]
|
|
285
|
+
};
|
|
260
286
|
case "TradingVerificationInput":
|
|
261
287
|
return objectSchema({
|
|
262
288
|
symbol: symbolSchema,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { buildCompatibilityReport } from "../contracts/compatibility.js";
|
|
3
3
|
import { ProductError } from "../errors/product-error.js";
|
|
4
|
-
const TRADING_DOMAINS = new Set(["
|
|
4
|
+
const TRADING_DOMAINS = new Set(["portfolio", "order", "position", "algo"]);
|
|
5
5
|
export function defaultSafetyPolicy() {
|
|
6
6
|
const policy = {
|
|
7
7
|
readOnly: process.env.RAPIDX_READ_ONLY === "true",
|
|
@@ -72,7 +72,7 @@ export function evaluateSafety(capability, input, policy, state = makeSafetyStat
|
|
|
72
72
|
return { allowed: false, code: "RCORE00001", reason: "leverage must be an integer from 1 to 125.", paramsHash };
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
|
-
if (capability.capabilityId === "
|
|
75
|
+
if (capability.capabilityId === "portfolio.set-position-mode") {
|
|
76
76
|
const mode = String(input.mode ?? "");
|
|
77
77
|
if (mode !== "BOTH" && mode !== "NET") {
|
|
78
78
|
return { allowed: false, code: "RCORE00001", reason: "mode must be BOTH or NET.", paramsHash };
|
|
@@ -124,7 +124,7 @@ function requiredTradeFields(capability, input) {
|
|
|
124
124
|
requireString(input, "algoType", missing);
|
|
125
125
|
}
|
|
126
126
|
break;
|
|
127
|
-
case "order.
|
|
127
|
+
case "order.replace":
|
|
128
128
|
requireOneOf(input, ["orderId", "clientOrderId"], "orderId or clientOrderId", missing);
|
|
129
129
|
if (!hasString(input, "price") && !hasString(input, "quantity")) {
|
|
130
130
|
missing.push("price or quantity");
|
|
@@ -146,11 +146,15 @@ function requiredTradeFields(capability, input) {
|
|
|
146
146
|
missing.push("leverage");
|
|
147
147
|
}
|
|
148
148
|
break;
|
|
149
|
-
case "
|
|
149
|
+
case "order.cancel-all":
|
|
150
|
+
break;
|
|
151
|
+
case "position.close-all":
|
|
152
|
+
break;
|
|
153
|
+
case "portfolio.set-position-mode":
|
|
150
154
|
requireString(input, "mode", missing);
|
|
151
155
|
requireString(input, "exchange", missing);
|
|
152
156
|
break;
|
|
153
|
-
case "algo.
|
|
157
|
+
case "algo.replace":
|
|
154
158
|
requireOneOf(input, ["algoOrderId", "clientOrderId"], "algoOrderId or clientOrderId", missing);
|
|
155
159
|
break;
|
|
156
160
|
case "algo.cancel":
|
|
@@ -8,10 +8,10 @@ export function buildLiveReadOnlySelfCheck(input = {}) {
|
|
|
8
8
|
const symbol = typeof input.symbol === "string" ? input.symbol : "BINANCE_PERP_BTC_USDT";
|
|
9
9
|
const probes = {
|
|
10
10
|
publicMarket: async () => executeRapidXCapability("market.ticker", { symbol }),
|
|
11
|
-
credentialAuth: async () => executeRapidXCapability("
|
|
12
|
-
accountRead: async () => executeRapidXCapability("
|
|
13
|
-
orderRead: async () => executeRapidXCapability("order.
|
|
14
|
-
positionRead: async () => executeRapidXCapability("position.
|
|
11
|
+
credentialAuth: async () => executeRapidXCapability("portfolio.overview", {}),
|
|
12
|
+
accountRead: async () => executeRapidXCapability("portfolio.assets", {}),
|
|
13
|
+
orderRead: async () => executeRapidXCapability("order.open-orders", {}),
|
|
14
|
+
positionRead: async () => executeRapidXCapability("position.query", {})
|
|
15
15
|
};
|
|
16
16
|
return { credential, probes };
|
|
17
17
|
}
|
|
@@ -77,7 +77,7 @@ async function buildMarketRules(input) {
|
|
|
77
77
|
};
|
|
78
78
|
}
|
|
79
79
|
async function queryOrder(order) {
|
|
80
|
-
const result = await executeRapidXCapability("order.
|
|
80
|
+
const result = await executeRapidXCapability("order.query", { orderId: order.orderId });
|
|
81
81
|
const data = extractDataObject(result);
|
|
82
82
|
const requestId = stringField(data, "clientOrderId") ?? order.requestId;
|
|
83
83
|
return {
|
|
@@ -89,8 +89,8 @@ async function queryOrder(order) {
|
|
|
89
89
|
async function cleanupCheck(input) {
|
|
90
90
|
const symbol = typeof input.symbol === "string" ? input.symbol : "BINANCE_PERP_BTC_USDT";
|
|
91
91
|
const [ordersResult, positionsResult] = await Promise.all([
|
|
92
|
-
executeRapidXCapability("order.
|
|
93
|
-
executeRapidXCapability("position.
|
|
92
|
+
executeRapidXCapability("order.open-orders", { symbol, pageSize: 20 }),
|
|
93
|
+
executeRapidXCapability("position.query", { symbol })
|
|
94
94
|
]);
|
|
95
95
|
const orders = extractList(extractDataObject(ordersResult));
|
|
96
96
|
const positions = extractArrayData(positionsResult);
|
|
@@ -11,8 +11,8 @@ export async function runPreviewPreflight(capabilityId, input, options = {}) {
|
|
|
11
11
|
return validateOrderPlacementPreflight(input, options);
|
|
12
12
|
case "order.cancel":
|
|
13
13
|
return validateOrderMutationPreflight(input, "cancel", options);
|
|
14
|
-
case "order.
|
|
15
|
-
return validateOrderMutationPreflight(input, "
|
|
14
|
+
case "order.replace":
|
|
15
|
+
return validateOrderMutationPreflight(input, "replace", options);
|
|
16
16
|
case "position.close":
|
|
17
17
|
return validatePositionClosePreflight(input, options);
|
|
18
18
|
default:
|
|
@@ -50,7 +50,7 @@ async function validateOrderMutationPreflight(input, action, options) {
|
|
|
50
50
|
throw new ProductError({
|
|
51
51
|
code: "RCORE22004",
|
|
52
52
|
status: "BLOCKED",
|
|
53
|
-
message: "ORDER_NOT_FOUND: order.
|
|
53
|
+
message: "ORDER_NOT_FOUND: order.query did not return an order for preview preflight."
|
|
54
54
|
});
|
|
55
55
|
}
|
|
56
56
|
const state = normalizeOrderState(order.orderState ?? order.state ?? order.status);
|
|
@@ -238,7 +238,7 @@ function makeRequestSummary(capabilityId, params) {
|
|
|
238
238
|
positionSide: params.positionSide
|
|
239
239
|
});
|
|
240
240
|
}
|
|
241
|
-
if (capabilityId === "
|
|
241
|
+
if (capabilityId === "portfolio.set-position-mode") {
|
|
242
242
|
return compactRecord({
|
|
243
243
|
action: "set_position_mode",
|
|
244
244
|
mode: params.mode,
|
|
@@ -274,7 +274,7 @@ function makeRiskNotes(capabilityId, params, automation) {
|
|
|
274
274
|
if (capabilityId === "position.close") {
|
|
275
275
|
notes.push("Do not pass side or quantity for position.close; RapidX determines BUY or SELL from the current position and closes the target symbol/positionSide.");
|
|
276
276
|
notes.push("position.close uses the RapidX close-position API and may execute as a market close with slippage.");
|
|
277
|
-
notes.push("order.
|
|
277
|
+
notes.push("order.query reduceOnly may not reflect the close-position API request; verify final exposure with position.query.");
|
|
278
278
|
}
|
|
279
279
|
return notes;
|
|
280
280
|
}
|
|
@@ -95,18 +95,18 @@ export async function runTradingVerification(rawInput, probes = {}) {
|
|
|
95
95
|
}
|
|
96
96
|
steps.push({ name: "query", status: "PASS", toolOrCommandEvidence: `${queried.orderId}:${queried.status}` });
|
|
97
97
|
let currentOrder = queried;
|
|
98
|
-
if (probes.
|
|
99
|
-
currentOrder = await probes.
|
|
100
|
-
steps.push({ name: "
|
|
98
|
+
if (probes.replaceOrder) {
|
|
99
|
+
currentOrder = await probes.replaceOrder(currentOrder);
|
|
100
|
+
steps.push({ name: "replace", status: currentOrder.status === "UNKNOWN" ? "NOT_VERIFIED" : "PASS", toolOrCommandEvidence: `${currentOrder.orderId}:${currentOrder.status}` });
|
|
101
101
|
if (currentOrder.status === "UNKNOWN") {
|
|
102
|
-
return { submittedRealOrder: true, status: "NOT_VERIFIED", cleanupStatus: "NOT_VERIFIED", steps, previewId: preview.previewId, errorCode: "RCORE23001", errorStage: "
|
|
102
|
+
return { submittedRealOrder: true, status: "NOT_VERIFIED", cleanupStatus: "NOT_VERIFIED", steps, previewId: preview.previewId, errorCode: "RCORE23001", errorStage: "replace", lastObservedOrderState: currentOrder.status };
|
|
103
103
|
}
|
|
104
104
|
}
|
|
105
105
|
else {
|
|
106
106
|
steps.push({
|
|
107
|
-
name: "
|
|
107
|
+
name: "replace",
|
|
108
108
|
status: "EXPECTED_ERROR",
|
|
109
|
-
toolOrCommandEvidence: "optional verify-live
|
|
109
|
+
toolOrCommandEvidence: "optional verify-live replace check skipped; order.replace remains available outside verify-live"
|
|
110
110
|
});
|
|
111
111
|
}
|
|
112
112
|
if (!probes.cancelOrder) {
|
|
@@ -122,7 +122,7 @@ export async function runTradingVerification(rawInput, probes = {}) {
|
|
|
122
122
|
steps.push({ name: "cancel", status: "PASS", toolOrCommandEvidence: cancelConfirmation.evidence });
|
|
123
123
|
if (!probes.cleanupCheck) {
|
|
124
124
|
steps.push({ name: "cleanup-check", status: "NOT_VERIFIED", toolOrCommandEvidence: "cleanupCheck probe missing" });
|
|
125
|
-
return { submittedRealOrder: true, status: "NOT_VERIFIED", cleanupStatus: "NOT_VERIFIED", steps, previewId: preview.previewId, errorCode: "RCORE24002", errorStage: "cleanup-check", recommendedAction: "Query order/
|
|
125
|
+
return { submittedRealOrder: true, status: "NOT_VERIFIED", cleanupStatus: "NOT_VERIFIED", steps, previewId: preview.previewId, errorCode: "RCORE24002", errorStage: "cleanup-check", recommendedAction: "Query order/open-orders and position/query before retrying verify-live." };
|
|
126
126
|
}
|
|
127
127
|
const cleanupConfirmation = await confirmCleanup(currentOrder, probes);
|
|
128
128
|
if (!cleanupConfirmation.confirmed) {
|
|
@@ -254,7 +254,7 @@ function cleanupFailureReport(steps, previewId, errorStage, lastObservedOrderSta
|
|
|
254
254
|
errorStage,
|
|
255
255
|
...(lastObservedOrderState ? { lastObservedOrderState } : {}),
|
|
256
256
|
expectedOrderStates: ["CANCELED", "EXPIRED", "REJECTED"],
|
|
257
|
-
recommendedAction: "Query order/
|
|
257
|
+
recommendedAction: "Query order/query, order/open-orders, and position/query before retrying; do not submit another verification until cleanup is confirmed."
|
|
258
258
|
};
|
|
259
259
|
}
|
|
260
260
|
function quantityForNotional(minNotional, price) {
|
package/dist/core/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const RAPIDX_VERSION = "1.0.
|
|
1
|
+
export const RAPIDX_VERSION = "1.0.32";
|
package/dist/mcp/tool-runner.js
CHANGED
|
@@ -136,8 +136,8 @@ export async function runMcpTool(toolName, input = {}) {
|
|
|
136
136
|
}
|
|
137
137
|
}
|
|
138
138
|
function concretePreviewTargetForTool(toolName) {
|
|
139
|
-
if (toolName === "rapidx/order/
|
|
140
|
-
return "order.
|
|
139
|
+
if (toolName === "rapidx/order/replace-preview") {
|
|
140
|
+
return "order.replace";
|
|
141
141
|
}
|
|
142
142
|
if (toolName === "rapidx/order/cancel-preview") {
|
|
143
143
|
return "order.cancel";
|
package/package.json
CHANGED
|
@@ -17,9 +17,9 @@ Supported conventions:
|
|
|
17
17
|
- Use stdin JSON when the host supports it.
|
|
18
18
|
- Do not create bridge scripts.
|
|
19
19
|
- Use `rapidx order place-preview` for `order.place`.
|
|
20
|
-
- Use `rapidx order
|
|
20
|
+
- Use `rapidx order replace-preview` for `order.replace`.
|
|
21
21
|
- Use `rapidx order cancel-preview` for `order.cancel`.
|
|
22
|
-
- Use `rapidx trade preview` with `targetCapabilityId` for non-order trade writes, including position,
|
|
22
|
+
- Use `rapidx trade preview` with `targetCapabilityId` for non-order trade writes, including position, portfolio, and algo writes.
|
|
23
23
|
- `rapidx trade preview` input is flat JSON; do not wrap target parameters under `params`.
|
|
24
24
|
- CLI preview ids are stored in the local CLI preview store. Do not submit MCP-created preview ids through CLI.
|
|
25
25
|
- Treat `maxNotional` as a safety upper bound, not as the target order amount. Check symbol `minNotional` before increasing a requested amount.
|
|
@@ -32,28 +32,28 @@ rapidx schema --json
|
|
|
32
32
|
rapidx update check --json
|
|
33
33
|
rapidx self-check --read-only --json
|
|
34
34
|
rapidx self-check --read-only --check-updates --json
|
|
35
|
-
rapidx
|
|
36
|
-
rapidx
|
|
35
|
+
rapidx portfolio overview --json
|
|
36
|
+
rapidx portfolio assets --input '{"exchangeType":"BINANCE"}' --json
|
|
37
37
|
rapidx order place-preview --input @/absolute/path/order-preview.json --json
|
|
38
|
-
rapidx order
|
|
38
|
+
rapidx order replace-preview --input @/absolute/path/order-replace-preview.json --json
|
|
39
39
|
rapidx order cancel-preview --input @/absolute/path/order-cancel-preview.json --json
|
|
40
40
|
rapidx trade preview --input @/absolute/path/trade-preview.json --json
|
|
41
41
|
rapidx position history --input @/absolute/path/position-history.json --json
|
|
42
|
-
rapidx
|
|
42
|
+
rapidx portfolio set-position-mode --input @/absolute/path/set-position-mode.json --json
|
|
43
43
|
```
|
|
44
44
|
|
|
45
45
|
`rapidx update check --json` reads the RapidX release manifest and caches the result locally. Use it during setup, review, or session startup. Trade submit paths should not perform a fresh network update check.
|
|
46
46
|
|
|
47
47
|
`rapidx schema --json` returns `capabilities` plus `inputSchemas`. Agents should read the concrete input schema before constructing write inputs.
|
|
48
48
|
|
|
49
|
-
`rapidx
|
|
49
|
+
`rapidx portfolio assets` reads `/api/v1/trading/portfolio/assets`. It is the canonical CLI command for portfolio asset balances.
|
|
50
50
|
|
|
51
|
-
`rapidx
|
|
51
|
+
`rapidx portfolio set-position-mode` is a trade write. Use it only when the user explicitly asks to change account position mode. It requires a matching preview token and a `continueConsentId` before execution.
|
|
52
52
|
|
|
53
|
-
`rapidx order cancel` is asynchronous. A successful response can mean cancel accepted but not terminal. Poll `rapidx order
|
|
53
|
+
`rapidx order cancel` is asynchronous. A successful response can mean cancel accepted but not terminal. Poll `rapidx order query --json` when `terminalStateConfirmed=false`.
|
|
54
54
|
|
|
55
|
-
When using `orderId`, pass the RapidX 16-digit numeric order id. Invalid `orderId` format is rejected locally as `INVALID_INPUT`. `clientOrderId` can be used instead and does not need to satisfy the `orderId` format. Preview commands for
|
|
55
|
+
When using `orderId`, pass the RapidX 16-digit numeric order id. Invalid `orderId` format is rejected locally as `INVALID_INPUT`. `clientOrderId` can be used instead and does not need to satisfy the `orderId` format. Preview commands for replace/cancel perform a RapidX readback after local format validation; valid-but-missing orders return `NOT_FOUND` or a blocked non-open state.
|
|
56
56
|
|
|
57
57
|
Automation mode still uses preview. Pass `automationMode=true` and the user's exact `automationConsentText` to preview only when the user has enabled automation in chat for the current scope.
|
|
58
58
|
|
|
59
|
-
`rapidx position close` is a close-position action. Do not pass `side` or `quantity`; RapidX determines BUY or SELL from the current position and closes the target symbol/positionSide. Use a reduce-only order flow for partial closes. Verify the final exposure with `rapidx position
|
|
59
|
+
`rapidx position close` is a close-position action. Do not pass `side` or `quantity`; RapidX determines BUY or SELL from the current position and closes the target symbol/positionSide. Use a reduce-only order flow for partial closes. Verify the final exposure with `rapidx position query --json`, and do not rely only on `order query` to interpret the close intent.
|
|
@@ -28,14 +28,14 @@ Key trading tools:
|
|
|
28
28
|
- `rapidx/update/check` reads the RapidX release manifest and returns current/latest CLI version, minimum write version, skills update advice, and upgrade commands.
|
|
29
29
|
- `rapidx/self-check` can include update state when called with `{"checkUpdates": true}`.
|
|
30
30
|
- `rapidx/order/preview` creates preview tokens for `order.place`.
|
|
31
|
-
- `rapidx/order/place-preview`, `rapidx/order/
|
|
32
|
-
- `rapidx/trade/preview` creates preview tokens for non-place trade writes by `targetCapabilityId`, including position,
|
|
31
|
+
- `rapidx/order/place-preview`, `rapidx/order/replace-preview`, and `rapidx/order/cancel-preview` are concrete order preview aliases. Preview responses include `confirmation.submitToken`; pass it as `continueConsentId` when submitting the matching write tool.
|
|
32
|
+
- `rapidx/trade/preview` creates preview tokens for non-place trade writes by `targetCapabilityId`, including position, portfolio, and algo writes.
|
|
33
33
|
- Preview ids are local to the running MCP server. Do not submit a CLI-created preview id through MCP, and do not submit an MCP-created preview id through CLI.
|
|
34
|
-
- `rapidx/order/cancel` returns cancel acceptance plus terminal-state guidance. Poll `rapidx/order/
|
|
34
|
+
- `rapidx/order/cancel` returns cancel acceptance plus terminal-state guidance. Poll `rapidx/order/query` when `terminalStateConfirmed=false`.
|
|
35
35
|
- Automation mode still uses preview. Set `automationMode=true` and pass the user's exact `automationConsentText` only when the user has enabled automation in chat for the current scope.
|
|
36
36
|
- `rapidx/position/history` reads historical positions.
|
|
37
37
|
- Hedge-mode order placement and verification use `positionSide="LONG"` or `positionSide="SHORT"` in the order or verify-live input. Do not use account mode switching as a substitute for order-level `positionSide`.
|
|
38
|
-
- `rapidx/
|
|
38
|
+
- `rapidx/portfolio/set-position-mode` changes account position mode and requires preview plus explicit continuation consent. Use it only when the user explicitly asks to change account position mode.
|
|
39
39
|
- `rapidx/trade/verify-live` runs the optional small real-trade verification flow with `explicitUserConsent` and parameter-bound `acceptedRiskText`; it creates its own internal preview and does not accept an external `previewId`. If `positionSide` is provided, `acceptedRiskText` must include that position side. `rapidx/trading-verification` remains supported as a compatibility alias.
|
|
40
40
|
|
|
41
41
|
Agents must discover the full tool list through `rapidx/tools` and must not invent tool names.
|
|
@@ -111,15 +111,15 @@ Do not treat a missing real call as success. The correct status is `NOT_VERIFIED
|
|
|
111
111
|
rapidx schema --json
|
|
112
112
|
```
|
|
113
113
|
|
|
114
|
-
For trade writes, create a preview before submit. Use `rapidx order place-preview` for `order.place`, `rapidx order
|
|
114
|
+
For trade writes, create a preview before submit. Use `rapidx order place-preview` for `order.place`, `rapidx order replace-preview` for `order.replace`, and `rapidx order cancel-preview` for `order.cancel`. Use flat JSON with `rapidx trade preview` and `targetCapabilityId` for non-order writes such as `position.set-leverage`, `position.close`, or `portfolio.set-position-mode`.
|
|
115
115
|
|
|
116
|
-
`rapidx schema --json` and `rapidx/tools` return concrete `inputSchemas`. For hedge-mode orders, use `positionSide="LONG"` or `positionSide="SHORT"` in the order or verify-live input. Use `
|
|
116
|
+
`rapidx schema --json` and `rapidx/tools` return concrete `inputSchemas`. For hedge-mode orders, use `positionSide="LONG"` or `positionSide="SHORT"` in the order or verify-live input. Use `portfolio.set-position-mode` only when the user explicitly asks to change account mode.
|
|
117
117
|
|
|
118
118
|
For clearer order flows, prefer the explicit aliases:
|
|
119
119
|
|
|
120
120
|
```bash
|
|
121
121
|
rapidx order place-preview --input '{"symbol":"BINANCE_PERP_BTC_USDT","side":"BUY","orderType":"LIMIT","price":"65000","quantity":"0.001","maxNotional":"100","clientOrderId":"example-001"}' --json
|
|
122
|
-
rapidx order
|
|
122
|
+
rapidx order replace-preview --input '{"orderId":"<order-id>","price":"64900"}' --json
|
|
123
123
|
rapidx order cancel-preview --input '{"orderId":"<order-id>"}' --json
|
|
124
124
|
rapidx trade preview --input '{"targetCapabilityId":"position.set-leverage","symbol":"BINANCE_PERP_BTC_USDT","leverage":5}' --json
|
|
125
125
|
```
|
|
@@ -128,10 +128,10 @@ When submitting the actual write, pass the returned `previewId` and use `confirm
|
|
|
128
128
|
|
|
129
129
|
Preview ids are runtime-local. Submit MCP previews through the same MCP server runtime, and submit CLI previews through the same CLI preview store.
|
|
130
130
|
|
|
131
|
-
`order.cancel` is asynchronous. If the cancel result says `terminalStateConfirmed=false`, poll `order
|
|
131
|
+
`order.cancel` is asynchronous. If the cancel result says `terminalStateConfirmed=false`, poll `order query` until a terminal state before claiming that the order is cancelled.
|
|
132
132
|
|
|
133
133
|
For automation, keep the preview-first flow. Use `automationMode=true` and the user's exact `automationConsentText` only after the user has enabled RapidX automation mode in chat for the current scope.
|
|
134
134
|
|
|
135
|
-
`maxNotional` is a safety upper bound, not the target order amount. If a requested amount is below the symbol `minNotional`, ask the user to confirm the larger amount before submitting. For `position.close`, do not pass `side` or `quantity`; RapidX determines the close side from the current position and closes the target symbol/positionSide. Use a reduce-only order flow for partial closes, then check final exposure with `position
|
|
135
|
+
`maxNotional` is a safety upper bound, not the target order amount. If a requested amount is below the symbol `minNotional`, ask the user to confirm the larger amount before submitting. For `position.close`, do not pass `side` or `quantity`; RapidX determines the close side from the current position and closes the target symbol/positionSide. Use a reduce-only order flow for partial closes, then check final exposure with `position query`.
|
|
136
136
|
|
|
137
137
|
Use `rapidx trade verify-live --json` only when the user explicitly authorizes a small real-trade verification. Include `acceptedRiskText` that names the exact symbol, side, positionSide when provided, maxNotional, real-order risk, and cancel cleanup behavior. The older `rapidx self-check trade-verify --json` command remains supported for compatibility.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Self-check
|
|
2
2
|
|
|
3
|
-
Read-only self-check verifies discovery, schema compatibility, public market access, credential auth,
|
|
3
|
+
Read-only self-check verifies discovery, schema compatibility, public market access, credential auth, portfolio assets, order open-orders, and position query when probes are available.
|
|
4
4
|
|
|
5
5
|
The self-check must never submit an order.
|
|
6
6
|
|
|
@@ -12,17 +12,19 @@ The canonical source is `rapidx schema --json` or `rapidx/tools`.
|
|
|
12
12
|
|
|
13
13
|
- `rapidx/order/preview`: preview for `order.place`.
|
|
14
14
|
- `rapidx/order/place-preview`: explicit alias for `order.place` preview. It returns `previewId` plus `confirmation.submitToken`.
|
|
15
|
-
- `rapidx/order/
|
|
15
|
+
- `rapidx/order/replace-preview`: explicit alias for `order.replace` preview. Submit `rapidx/order/replace` with unchanged parameters, `previewId`, and `continueConsentId=confirmation.submitToken`.
|
|
16
16
|
- `rapidx/order/cancel-preview`: explicit alias for `order.cancel` preview. Submit `rapidx/order/cancel` with unchanged parameters, `previewId`, and `continueConsentId=confirmation.submitToken`.
|
|
17
|
-
- `rapidx/trade/preview`: generic preview for non-place trade writes, including position writes,
|
|
17
|
+
- `rapidx/trade/preview`: generic preview for non-place trade writes, including position writes, portfolio writes, and algo writes. Pass `targetCapabilityId`, then submit the target tool with unchanged parameters, `previewId`, and `continueConsentId`.
|
|
18
18
|
|
|
19
19
|
## Read Tools
|
|
20
20
|
|
|
21
21
|
- Market reads: ticker, orderbook, klines, funding rate, mark price, symbol info, and open interest.
|
|
22
|
-
-
|
|
23
|
-
- Order reads:
|
|
24
|
-
- Position reads:
|
|
25
|
-
- Algo reads:
|
|
22
|
+
- Portfolio reads: overview, assets, statement, user fee rate, and position bracket.
|
|
23
|
+
- Order reads: query, open-orders, history, and executions.
|
|
24
|
+
- Position reads: query, position history, and get-leverage.
|
|
25
|
+
- Algo reads: open-orders and query.
|
|
26
|
+
|
|
27
|
+
`open-orders` means current non-terminal orders, not "open an order". These orders may still be fillable, replaceable, or cancelable. `algo/open-orders` means current non-terminal algo orders such as conditional or TPSL orders that have not triggered, been canceled, or otherwise ended.
|
|
26
28
|
|
|
27
29
|
## Symbol Format
|
|
28
30
|
|
|
@@ -38,26 +40,26 @@ Public market adapters may call venue APIs with official venue symbols such as `
|
|
|
38
40
|
|
|
39
41
|
## Write Tools
|
|
40
42
|
|
|
41
|
-
- Order writes: place,
|
|
42
|
-
- Position writes: close and set leverage.
|
|
43
|
-
-
|
|
44
|
-
- Algo writes: place,
|
|
43
|
+
- Order writes: place, replace, cancel, and cancel-all.
|
|
44
|
+
- Position writes: close, close-all, and set leverage.
|
|
45
|
+
- Portfolio writes: set position mode.
|
|
46
|
+
- Algo writes: place, replace, and cancel.
|
|
45
47
|
- Live verification: `rapidx/trade/verify-live` is the clearer alias for the small real-trade verification flow. It submits a real verification order and requires `acceptedRiskText` bound to the exact symbol, side, maxNotional, real-order risk, and cancel cleanup behavior. If `positionSide` is provided, `acceptedRiskText` must include it. `rapidx/trading-verification` remains supported for compatibility.
|
|
46
48
|
|
|
47
49
|
All write tools require preview where the schema marks `previewRequired: true`.
|
|
48
50
|
MARKET order writes are allowed after preview and consent. Preview includes immediate-execution and slippage risk notes; do not replace MARKET with a synthetic limit strategy unless the user explicitly asks for that order style.
|
|
49
51
|
|
|
50
|
-
For hedge-mode order placement, pass `positionSide="LONG"` or `positionSide="SHORT"` on the order or verify-live input. Use `
|
|
52
|
+
For hedge-mode order placement, pass `positionSide="LONG"` or `positionSide="SHORT"` on the order or verify-live input. Use `portfolio.set-position-mode` only when the user explicitly asks to change the account position mode.
|
|
51
53
|
|
|
52
54
|
Preview ids are runtime-local. A preview created by MCP must be submitted through the same MCP server runtime. A preview created by CLI must be submitted through the same CLI preview store. Do not mix MCP preview ids with CLI submit commands, or the reverse.
|
|
53
55
|
|
|
54
|
-
`order.cancel` is asynchronous. A successful cancel response means the cancel request was accepted; it may not prove a terminal order state yet. The response includes `cancelAccepted`, `terminalStateConfirmed`, `lastObservedOrderState`, and `recommendedAction`. Poll `order.
|
|
56
|
+
`order.cancel` is asynchronous. A successful cancel response means the cancel request was accepted; it may not prove a terminal order state yet. The response includes `cancelAccepted`, `terminalStateConfirmed`, `lastObservedOrderState`, and `recommendedAction`. Poll `order.query` until `CANCELED`, `REJECTED`, `EXPIRED`, or timeout when `terminalStateConfirmed=false`.
|
|
55
57
|
|
|
56
|
-
Order identifiers use two validation layers. If `orderId` is provided, RapidX validates it locally as a 16-digit numeric id and returns `INVALID_INPUT` before any upstream call when the format is wrong. If `clientOrderId` is provided instead, do not apply `orderId` validation. For `order.
|
|
58
|
+
Order identifiers use two validation layers. If `orderId` is provided, RapidX validates it locally as a 16-digit numeric id and returns `INVALID_INPUT` before any upstream call when the format is wrong. If `clientOrderId` is provided instead, do not apply `orderId` validation. For `order.query`, `order.replace-preview`, and `order.cancel-preview`, a syntactically valid `orderId` or `clientOrderId` is checked through RapidX readback; missing or non-open orders return `NOT_FOUND` or `BLOCKED` depending on the observed state.
|
|
57
59
|
|
|
58
60
|
For automation, keep preview-first execution. Set `automationMode=true` and pass the user's exact `automationConsentText` only when the user has explicitly enabled RapidX automation mode in chat. The preview response still returns `confirmation.submitToken`; automation mode only means the agent may use that submit token without asking for another per-order chat confirmation within the authorized scope.
|
|
59
61
|
|
|
60
|
-
For TPSL or conditional algo orders, use `rapidx/trade/preview` with `targetCapabilityId="algo.place"`, then submit `rapidx/algo/place`. `conditionType="ENTIRE_CLOSE_POSITION"` may use `orderType="MARKET"` without `quantity` or `amount`; provide at least one take-profit or stop-loss trigger and verify with `rapidx/algo/
|
|
62
|
+
For TPSL or conditional algo orders, use `rapidx/trade/preview` with `targetCapabilityId="algo.place"`, then submit `rapidx/algo/place`. `conditionType="ENTIRE_CLOSE_POSITION"` may use `orderType="MARKET"` without `quantity` or `amount`; provide at least one take-profit or stop-loss trigger and verify with `rapidx/algo/open-orders`.
|
|
61
63
|
|
|
62
64
|
## Result Statuses
|
|
63
65
|
|
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.0.
|
|
2
|
+
"version": "1.0.32",
|
|
3
3
|
"artifacts": [
|
|
4
4
|
{
|
|
5
5
|
"name": "rapidx-mcp-registry",
|
|
6
6
|
"path": "packages/distribution/registry/rapidx.mcp.json",
|
|
7
7
|
"channel": "offline",
|
|
8
|
-
"checksum": "sha256:
|
|
8
|
+
"checksum": "sha256:b75ee5a765902c45f13614cdaf906633590456480fe91174ecee2422048aaf93",
|
|
9
9
|
"status": "ready"
|
|
10
10
|
},
|
|
11
11
|
{
|
|
12
12
|
"name": "rapidx-quickstart-doc",
|
|
13
13
|
"path": "packages/distribution/docs/quickstart.md",
|
|
14
14
|
"channel": "offline",
|
|
15
|
-
"checksum": "sha256:
|
|
15
|
+
"checksum": "sha256:e7cb18db9ce37a94ff1489d951f23b5f0407fd9e1f28f47f8ec13681f5760ccc",
|
|
16
16
|
"status": "ready"
|
|
17
17
|
},
|
|
18
18
|
{
|
|
19
19
|
"name": "rapidx-tools-doc",
|
|
20
20
|
"path": "packages/distribution/docs/tools.md",
|
|
21
21
|
"channel": "offline",
|
|
22
|
-
"checksum": "sha256:
|
|
22
|
+
"checksum": "sha256:d7e378d95127c2c62bb8db3a58cfa8a5f80ab2cf523ee530144ddfb9cca7bd96",
|
|
23
23
|
"status": "ready"
|
|
24
24
|
}
|
|
25
25
|
]
|