okx-trade-cli 1.0.2 → 1.0.4
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/index.js +1148 -27
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6,6 +6,8 @@ import { createRequire } from "module";
|
|
|
6
6
|
|
|
7
7
|
// ../core/dist/index.js
|
|
8
8
|
import { createHmac } from "crypto";
|
|
9
|
+
import path from "path";
|
|
10
|
+
import os from "os";
|
|
9
11
|
import { readFileSync, existsSync } from "fs";
|
|
10
12
|
import { join } from "path";
|
|
11
13
|
import { homedir } from "os";
|
|
@@ -24,6 +26,7 @@ var OkxMcpError = class extends Error {
|
|
|
24
26
|
code;
|
|
25
27
|
suggestion;
|
|
26
28
|
endpoint;
|
|
29
|
+
traceId;
|
|
27
30
|
constructor(type, message, options) {
|
|
28
31
|
super(message, options?.cause ? { cause: options.cause } : void 0);
|
|
29
32
|
this.name = type;
|
|
@@ -31,6 +34,7 @@ var OkxMcpError = class extends Error {
|
|
|
31
34
|
this.code = options?.code;
|
|
32
35
|
this.suggestion = options?.suggestion;
|
|
33
36
|
this.endpoint = options?.endpoint;
|
|
37
|
+
this.traceId = options?.traceId;
|
|
34
38
|
}
|
|
35
39
|
};
|
|
36
40
|
var ConfigError = class extends OkxMcpError {
|
|
@@ -39,13 +43,13 @@ var ConfigError = class extends OkxMcpError {
|
|
|
39
43
|
}
|
|
40
44
|
};
|
|
41
45
|
var RateLimitError = class extends OkxMcpError {
|
|
42
|
-
constructor(message, suggestion, endpoint) {
|
|
43
|
-
super("RateLimitError", message, { suggestion, endpoint });
|
|
46
|
+
constructor(message, suggestion, endpoint, traceId) {
|
|
47
|
+
super("RateLimitError", message, { suggestion, endpoint, traceId });
|
|
44
48
|
}
|
|
45
49
|
};
|
|
46
50
|
var AuthenticationError = class extends OkxMcpError {
|
|
47
|
-
constructor(message, suggestion, endpoint) {
|
|
48
|
-
super("AuthenticationError", message, { suggestion, endpoint });
|
|
51
|
+
constructor(message, suggestion, endpoint, traceId) {
|
|
52
|
+
super("AuthenticationError", message, { suggestion, endpoint, traceId });
|
|
49
53
|
}
|
|
50
54
|
};
|
|
51
55
|
var OkxApiError = class extends OkxMcpError {
|
|
@@ -71,6 +75,7 @@ function toToolErrorPayload(error, fallbackEndpoint) {
|
|
|
71
75
|
message: error.message,
|
|
72
76
|
suggestion: error.suggestion,
|
|
73
77
|
endpoint: error.endpoint ?? fallbackEndpoint,
|
|
78
|
+
traceId: error.traceId,
|
|
74
79
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
75
80
|
};
|
|
76
81
|
}
|
|
@@ -154,6 +159,9 @@ var RateLimiter = class {
|
|
|
154
159
|
function isDefined(value) {
|
|
155
160
|
return value !== void 0 && value !== null;
|
|
156
161
|
}
|
|
162
|
+
function extractTraceId(headers) {
|
|
163
|
+
return headers.get("x-trace-id") ?? headers.get("x-request-id") ?? headers.get("traceid") ?? void 0;
|
|
164
|
+
}
|
|
157
165
|
function stringifyQueryValue(value) {
|
|
158
166
|
if (Array.isArray(value)) {
|
|
159
167
|
return value.map((item) => String(item)).join(",");
|
|
@@ -180,28 +188,28 @@ var OkxRestClient = class {
|
|
|
180
188
|
constructor(config) {
|
|
181
189
|
this.config = config;
|
|
182
190
|
}
|
|
183
|
-
async publicGet(
|
|
191
|
+
async publicGet(path3, query, rateLimit) {
|
|
184
192
|
return this.request({
|
|
185
193
|
method: "GET",
|
|
186
|
-
path,
|
|
194
|
+
path: path3,
|
|
187
195
|
auth: "public",
|
|
188
196
|
query,
|
|
189
197
|
rateLimit
|
|
190
198
|
});
|
|
191
199
|
}
|
|
192
|
-
async privateGet(
|
|
200
|
+
async privateGet(path3, query, rateLimit) {
|
|
193
201
|
return this.request({
|
|
194
202
|
method: "GET",
|
|
195
|
-
path,
|
|
203
|
+
path: path3,
|
|
196
204
|
auth: "private",
|
|
197
205
|
query,
|
|
198
206
|
rateLimit
|
|
199
207
|
});
|
|
200
208
|
}
|
|
201
|
-
async privatePost(
|
|
209
|
+
async privatePost(path3, body, rateLimit) {
|
|
202
210
|
return this.request({
|
|
203
211
|
method: "POST",
|
|
204
|
-
path,
|
|
212
|
+
path: path3,
|
|
205
213
|
auth: "private",
|
|
206
214
|
body,
|
|
207
215
|
rateLimit
|
|
@@ -220,6 +228,9 @@ var OkxRestClient = class {
|
|
|
220
228
|
"Content-Type": "application/json",
|
|
221
229
|
Accept: "application/json"
|
|
222
230
|
});
|
|
231
|
+
if (this.config.userAgent) {
|
|
232
|
+
headers.set("User-Agent", this.config.userAgent);
|
|
233
|
+
}
|
|
223
234
|
if (config.auth === "private") {
|
|
224
235
|
if (!this.config.hasAuth) {
|
|
225
236
|
throw new ConfigError(
|
|
@@ -259,6 +270,7 @@ var OkxRestClient = class {
|
|
|
259
270
|
);
|
|
260
271
|
}
|
|
261
272
|
const rawText = await response.text();
|
|
273
|
+
const traceId = extractTraceId(response.headers);
|
|
262
274
|
let parsed;
|
|
263
275
|
try {
|
|
264
276
|
parsed = rawText ? JSON.parse(rawText) : {};
|
|
@@ -270,7 +282,8 @@ var OkxRestClient = class {
|
|
|
270
282
|
{
|
|
271
283
|
code: String(response.status),
|
|
272
284
|
endpoint: `${config.method} ${config.path}`,
|
|
273
|
-
suggestion: "Verify endpoint path and request parameters."
|
|
285
|
+
suggestion: "Verify endpoint path and request parameters.",
|
|
286
|
+
traceId
|
|
274
287
|
}
|
|
275
288
|
);
|
|
276
289
|
}
|
|
@@ -286,7 +299,8 @@ var OkxRestClient = class {
|
|
|
286
299
|
{
|
|
287
300
|
code: String(response.status),
|
|
288
301
|
endpoint: `${config.method} ${config.path}`,
|
|
289
|
-
suggestion: "Retry later or verify endpoint parameters."
|
|
302
|
+
suggestion: "Retry later or verify endpoint parameters.",
|
|
303
|
+
traceId
|
|
290
304
|
}
|
|
291
305
|
);
|
|
292
306
|
}
|
|
@@ -297,12 +311,14 @@ var OkxRestClient = class {
|
|
|
297
311
|
throw new AuthenticationError(
|
|
298
312
|
message,
|
|
299
313
|
"Check API key, secret, passphrase and permissions.",
|
|
300
|
-
`${config.method} ${config.path}
|
|
314
|
+
`${config.method} ${config.path}`,
|
|
315
|
+
traceId
|
|
301
316
|
);
|
|
302
317
|
}
|
|
303
318
|
throw new OkxApiError(message, {
|
|
304
319
|
code: responseCode,
|
|
305
|
-
endpoint: `${config.method} ${config.path}
|
|
320
|
+
endpoint: `${config.method} ${config.path}`,
|
|
321
|
+
traceId
|
|
306
322
|
});
|
|
307
323
|
}
|
|
308
324
|
return {
|
|
@@ -313,21 +329,24 @@ var OkxRestClient = class {
|
|
|
313
329
|
};
|
|
314
330
|
}
|
|
315
331
|
};
|
|
332
|
+
var DEFAULT_LOG_DIR = path.join(os.homedir(), ".okx", "logs");
|
|
316
333
|
var OKX_API_BASE_URL = "https://www.okx.com";
|
|
317
334
|
var MODULES = [
|
|
318
335
|
"market",
|
|
319
336
|
"spot",
|
|
320
337
|
"swap",
|
|
321
|
-
"
|
|
338
|
+
"futures",
|
|
339
|
+
"account",
|
|
340
|
+
"bot"
|
|
322
341
|
];
|
|
323
342
|
var DEFAULT_MODULES = ["spot", "swap", "account"];
|
|
324
343
|
function configFilePath() {
|
|
325
344
|
return join(homedir(), ".okx", "config.toml");
|
|
326
345
|
}
|
|
327
346
|
function readTomlProfile(profileName) {
|
|
328
|
-
const
|
|
329
|
-
if (!existsSync(
|
|
330
|
-
const raw = readFileSync(
|
|
347
|
+
const path3 = configFilePath();
|
|
348
|
+
if (!existsSync(path3)) return {};
|
|
349
|
+
const raw = readFileSync(path3, "utf-8");
|
|
331
350
|
const config = parse(raw);
|
|
332
351
|
const name = profileName ?? config.default_profile ?? "default";
|
|
333
352
|
return config.profiles?.[name] ?? {};
|
|
@@ -394,7 +413,8 @@ function loadConfig(cli) {
|
|
|
394
413
|
timeoutMs: Math.floor(rawTimeout),
|
|
395
414
|
modules: parseModuleList(cli.modules),
|
|
396
415
|
readOnly: cli.readOnly,
|
|
397
|
-
demo
|
|
416
|
+
demo,
|
|
417
|
+
userAgent: cli.userAgent
|
|
398
418
|
};
|
|
399
419
|
}
|
|
400
420
|
var CACHE_FILE = join2(homedir2(), ".okx", "update-check.json");
|
|
@@ -471,7 +491,8 @@ function loadProfileConfig(opts) {
|
|
|
471
491
|
profile: opts.profile,
|
|
472
492
|
modules: opts.modules,
|
|
473
493
|
readOnly: opts.readOnly ?? false,
|
|
474
|
-
demo: opts.demo ?? false
|
|
494
|
+
demo: opts.demo ?? false,
|
|
495
|
+
userAgent: opts.userAgent
|
|
475
496
|
});
|
|
476
497
|
}
|
|
477
498
|
|
|
@@ -512,6 +533,153 @@ function printKv(obj, indent = 0) {
|
|
|
512
533
|
}
|
|
513
534
|
|
|
514
535
|
// src/commands/market.ts
|
|
536
|
+
async function cmdMarketInstruments(client, opts) {
|
|
537
|
+
const params = { instType: opts.instType };
|
|
538
|
+
if (opts.instId) params["instId"] = opts.instId;
|
|
539
|
+
const res = await client.publicGet("/api/v5/public/instruments", params);
|
|
540
|
+
const items = res.data;
|
|
541
|
+
if (opts.json) return printJson(items);
|
|
542
|
+
printTable(
|
|
543
|
+
(items ?? []).slice(0, 50).map((t) => ({
|
|
544
|
+
instId: t["instId"],
|
|
545
|
+
ctVal: t["ctVal"],
|
|
546
|
+
lotSz: t["lotSz"],
|
|
547
|
+
minSz: t["minSz"],
|
|
548
|
+
tickSz: t["tickSz"],
|
|
549
|
+
state: t["state"]
|
|
550
|
+
}))
|
|
551
|
+
);
|
|
552
|
+
}
|
|
553
|
+
async function cmdMarketFundingRate(client, instId, opts) {
|
|
554
|
+
if (opts.history) {
|
|
555
|
+
const params = { instId };
|
|
556
|
+
if (opts.limit) params["limit"] = String(opts.limit);
|
|
557
|
+
const res = await client.publicGet("/api/v5/public/funding-rate-history", params);
|
|
558
|
+
const items = res.data;
|
|
559
|
+
if (opts.json) return printJson(items);
|
|
560
|
+
printTable(
|
|
561
|
+
(items ?? []).map((r) => ({
|
|
562
|
+
instId: r["instId"],
|
|
563
|
+
fundingRate: r["fundingRate"],
|
|
564
|
+
realizedRate: r["realizedRate"],
|
|
565
|
+
fundingTime: new Date(Number(r["fundingTime"])).toLocaleString()
|
|
566
|
+
}))
|
|
567
|
+
);
|
|
568
|
+
} else {
|
|
569
|
+
const res = await client.publicGet("/api/v5/public/funding-rate", { instId });
|
|
570
|
+
const items = res.data;
|
|
571
|
+
if (opts.json) return printJson(items);
|
|
572
|
+
const r = items?.[0];
|
|
573
|
+
if (!r) {
|
|
574
|
+
process.stdout.write("No data\n");
|
|
575
|
+
return;
|
|
576
|
+
}
|
|
577
|
+
printKv({
|
|
578
|
+
instId: r["instId"],
|
|
579
|
+
fundingRate: r["fundingRate"],
|
|
580
|
+
nextFundingRate: r["nextFundingRate"],
|
|
581
|
+
fundingTime: new Date(Number(r["fundingTime"])).toLocaleString(),
|
|
582
|
+
nextFundingTime: new Date(Number(r["nextFundingTime"])).toLocaleString()
|
|
583
|
+
});
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
async function cmdMarketMarkPrice(client, opts) {
|
|
587
|
+
const params = { instType: opts.instType };
|
|
588
|
+
if (opts.instId) params["instId"] = opts.instId;
|
|
589
|
+
const res = await client.publicGet("/api/v5/public/mark-price", params);
|
|
590
|
+
const items = res.data;
|
|
591
|
+
if (opts.json) return printJson(items);
|
|
592
|
+
printTable(
|
|
593
|
+
(items ?? []).map((r) => ({
|
|
594
|
+
instId: r["instId"],
|
|
595
|
+
instType: r["instType"],
|
|
596
|
+
markPx: r["markPx"],
|
|
597
|
+
ts: new Date(Number(r["ts"])).toLocaleString()
|
|
598
|
+
}))
|
|
599
|
+
);
|
|
600
|
+
}
|
|
601
|
+
async function cmdMarketTrades(client, instId, opts) {
|
|
602
|
+
const params = { instId };
|
|
603
|
+
if (opts.limit) params["limit"] = String(opts.limit);
|
|
604
|
+
const res = await client.publicGet("/api/v5/market/trades", params);
|
|
605
|
+
const items = res.data;
|
|
606
|
+
if (opts.json) return printJson(items);
|
|
607
|
+
printTable(
|
|
608
|
+
(items ?? []).map((t) => ({
|
|
609
|
+
tradeId: t["tradeId"],
|
|
610
|
+
px: t["px"],
|
|
611
|
+
sz: t["sz"],
|
|
612
|
+
side: t["side"],
|
|
613
|
+
ts: new Date(Number(t["ts"])).toLocaleString()
|
|
614
|
+
}))
|
|
615
|
+
);
|
|
616
|
+
}
|
|
617
|
+
async function cmdMarketIndexTicker(client, opts) {
|
|
618
|
+
const params = {};
|
|
619
|
+
if (opts.instId) params["instId"] = opts.instId;
|
|
620
|
+
if (opts.quoteCcy) params["quoteCcy"] = opts.quoteCcy;
|
|
621
|
+
const res = await client.publicGet("/api/v5/market/index-tickers", params);
|
|
622
|
+
const items = res.data;
|
|
623
|
+
if (opts.json) return printJson(items);
|
|
624
|
+
printTable(
|
|
625
|
+
(items ?? []).map((t) => ({
|
|
626
|
+
instId: t["instId"],
|
|
627
|
+
idxPx: t["idxPx"],
|
|
628
|
+
high24h: t["high24h"],
|
|
629
|
+
low24h: t["low24h"],
|
|
630
|
+
ts: new Date(Number(t["ts"])).toLocaleString()
|
|
631
|
+
}))
|
|
632
|
+
);
|
|
633
|
+
}
|
|
634
|
+
async function cmdMarketIndexCandles(client, instId, opts) {
|
|
635
|
+
const path3 = opts.history ? "/api/v5/market/history-index-candles" : "/api/v5/market/index-candles";
|
|
636
|
+
const params = { instId };
|
|
637
|
+
if (opts.bar) params["bar"] = opts.bar;
|
|
638
|
+
if (opts.limit) params["limit"] = String(opts.limit);
|
|
639
|
+
const res = await client.publicGet(path3, params);
|
|
640
|
+
const candles = res.data;
|
|
641
|
+
if (opts.json) return printJson(candles);
|
|
642
|
+
printTable(
|
|
643
|
+
(candles ?? []).map(([ts, o, h, l, c]) => ({
|
|
644
|
+
time: new Date(Number(ts)).toLocaleString(),
|
|
645
|
+
open: o,
|
|
646
|
+
high: h,
|
|
647
|
+
low: l,
|
|
648
|
+
close: c
|
|
649
|
+
}))
|
|
650
|
+
);
|
|
651
|
+
}
|
|
652
|
+
async function cmdMarketPriceLimit(client, instId, json) {
|
|
653
|
+
const res = await client.publicGet("/api/v5/public/price-limit", { instId });
|
|
654
|
+
const items = res.data;
|
|
655
|
+
if (json) return printJson(items);
|
|
656
|
+
const r = items?.[0];
|
|
657
|
+
if (!r) {
|
|
658
|
+
process.stdout.write("No data\n");
|
|
659
|
+
return;
|
|
660
|
+
}
|
|
661
|
+
printKv({
|
|
662
|
+
instId: r["instId"],
|
|
663
|
+
buyLmt: r["buyLmt"],
|
|
664
|
+
sellLmt: r["sellLmt"],
|
|
665
|
+
ts: new Date(Number(r["ts"])).toLocaleString()
|
|
666
|
+
});
|
|
667
|
+
}
|
|
668
|
+
async function cmdMarketOpenInterest(client, opts) {
|
|
669
|
+
const params = { instType: opts.instType };
|
|
670
|
+
if (opts.instId) params["instId"] = opts.instId;
|
|
671
|
+
const res = await client.publicGet("/api/v5/public/open-interest", params);
|
|
672
|
+
const items = res.data;
|
|
673
|
+
if (opts.json) return printJson(items);
|
|
674
|
+
printTable(
|
|
675
|
+
(items ?? []).map((r) => ({
|
|
676
|
+
instId: r["instId"],
|
|
677
|
+
oi: r["oi"],
|
|
678
|
+
oiCcy: r["oiCcy"],
|
|
679
|
+
ts: new Date(Number(r["ts"])).toLocaleString()
|
|
680
|
+
}))
|
|
681
|
+
);
|
|
682
|
+
}
|
|
515
683
|
async function cmdMarketTicker(client, instId, json) {
|
|
516
684
|
const res = await client.publicGet("/api/v5/market/ticker", { instId });
|
|
517
685
|
const items = res.data;
|
|
@@ -600,6 +768,187 @@ async function cmdAccountBalance(client, ccy, json) {
|
|
|
600
768
|
}))
|
|
601
769
|
);
|
|
602
770
|
}
|
|
771
|
+
async function cmdAccountAssetBalance(client, ccy, json) {
|
|
772
|
+
const params = {};
|
|
773
|
+
if (ccy) params["ccy"] = ccy;
|
|
774
|
+
const res = await client.privateGet("/api/v5/asset/balances", params);
|
|
775
|
+
const data = res.data;
|
|
776
|
+
if (json) return printJson(data);
|
|
777
|
+
printTable(
|
|
778
|
+
(data ?? []).filter((r) => Number(r["bal"]) > 0).map((r) => ({
|
|
779
|
+
ccy: r["ccy"],
|
|
780
|
+
bal: r["bal"],
|
|
781
|
+
availBal: r["availBal"],
|
|
782
|
+
frozenBal: r["frozenBal"]
|
|
783
|
+
}))
|
|
784
|
+
);
|
|
785
|
+
}
|
|
786
|
+
async function cmdAccountPositions(client, opts) {
|
|
787
|
+
const params = {};
|
|
788
|
+
if (opts.instType) params["instType"] = opts.instType;
|
|
789
|
+
if (opts.instId) params["instId"] = opts.instId;
|
|
790
|
+
const res = await client.privateGet("/api/v5/account/positions", params);
|
|
791
|
+
const positions = res.data;
|
|
792
|
+
if (opts.json) return printJson(positions);
|
|
793
|
+
const open = (positions ?? []).filter((p) => Number(p["pos"]) !== 0);
|
|
794
|
+
if (!open.length) {
|
|
795
|
+
process.stdout.write("No open positions\n");
|
|
796
|
+
return;
|
|
797
|
+
}
|
|
798
|
+
printTable(
|
|
799
|
+
open.map((p) => ({
|
|
800
|
+
instId: p["instId"],
|
|
801
|
+
instType: p["instType"],
|
|
802
|
+
side: p["posSide"],
|
|
803
|
+
pos: p["pos"],
|
|
804
|
+
avgPx: p["avgPx"],
|
|
805
|
+
upl: p["upl"],
|
|
806
|
+
lever: p["lever"]
|
|
807
|
+
}))
|
|
808
|
+
);
|
|
809
|
+
}
|
|
810
|
+
async function cmdAccountBills(client, opts) {
|
|
811
|
+
const endpoint = opts.archive ? "/api/v5/account/bills-archive" : "/api/v5/account/bills";
|
|
812
|
+
const params = {};
|
|
813
|
+
if (opts.instType) params["instType"] = opts.instType;
|
|
814
|
+
if (opts.ccy) params["ccy"] = opts.ccy;
|
|
815
|
+
if (opts.limit) params["limit"] = String(opts.limit);
|
|
816
|
+
const res = await client.privateGet(endpoint, params);
|
|
817
|
+
const bills = res.data;
|
|
818
|
+
if (opts.json) return printJson(bills);
|
|
819
|
+
printTable(
|
|
820
|
+
(bills ?? []).map((b) => ({
|
|
821
|
+
billId: b["billId"],
|
|
822
|
+
instId: b["instId"],
|
|
823
|
+
type: b["type"],
|
|
824
|
+
ccy: b["ccy"],
|
|
825
|
+
balChg: b["balChg"],
|
|
826
|
+
bal: b["bal"],
|
|
827
|
+
ts: new Date(Number(b["ts"])).toLocaleString()
|
|
828
|
+
}))
|
|
829
|
+
);
|
|
830
|
+
}
|
|
831
|
+
async function cmdAccountFees(client, opts) {
|
|
832
|
+
const params = { instType: opts.instType };
|
|
833
|
+
if (opts.instId) params["instId"] = opts.instId;
|
|
834
|
+
const res = await client.privateGet("/api/v5/account/trade-fee", params);
|
|
835
|
+
const data = res.data;
|
|
836
|
+
if (opts.json) return printJson(data);
|
|
837
|
+
const fee = data?.[0];
|
|
838
|
+
if (!fee) {
|
|
839
|
+
process.stdout.write("No data\n");
|
|
840
|
+
return;
|
|
841
|
+
}
|
|
842
|
+
printKv({
|
|
843
|
+
level: fee["level"],
|
|
844
|
+
maker: fee["maker"],
|
|
845
|
+
taker: fee["taker"],
|
|
846
|
+
makerU: fee["makerU"],
|
|
847
|
+
takerU: fee["takerU"],
|
|
848
|
+
ts: new Date(Number(fee["ts"])).toLocaleString()
|
|
849
|
+
});
|
|
850
|
+
}
|
|
851
|
+
async function cmdAccountConfig(client, json) {
|
|
852
|
+
const res = await client.privateGet("/api/v5/account/config", {});
|
|
853
|
+
const data = res.data;
|
|
854
|
+
if (json) return printJson(data);
|
|
855
|
+
const cfg = data?.[0];
|
|
856
|
+
if (!cfg) {
|
|
857
|
+
process.stdout.write("No data\n");
|
|
858
|
+
return;
|
|
859
|
+
}
|
|
860
|
+
printKv({
|
|
861
|
+
uid: cfg["uid"],
|
|
862
|
+
acctLv: cfg["acctLv"],
|
|
863
|
+
posMode: cfg["posMode"],
|
|
864
|
+
autoLoan: cfg["autoLoan"],
|
|
865
|
+
greeksType: cfg["greeksType"],
|
|
866
|
+
level: cfg["level"],
|
|
867
|
+
levelTmp: cfg["levelTmp"]
|
|
868
|
+
});
|
|
869
|
+
}
|
|
870
|
+
async function cmdAccountSetPositionMode(client, posMode, json) {
|
|
871
|
+
const res = await client.privatePost("/api/v5/account/set-position-mode", { posMode });
|
|
872
|
+
if (json) return printJson(res.data);
|
|
873
|
+
const r = res.data[0];
|
|
874
|
+
process.stdout.write(`Position mode set: ${r?.["posMode"]}
|
|
875
|
+
`);
|
|
876
|
+
}
|
|
877
|
+
async function cmdAccountMaxSize(client, opts) {
|
|
878
|
+
const params = { instId: opts.instId, tdMode: opts.tdMode };
|
|
879
|
+
if (opts.px) params["px"] = opts.px;
|
|
880
|
+
const res = await client.privateGet("/api/v5/account/max-size", params);
|
|
881
|
+
const data = res.data;
|
|
882
|
+
if (opts.json) return printJson(data);
|
|
883
|
+
const r = data?.[0];
|
|
884
|
+
if (!r) {
|
|
885
|
+
process.stdout.write("No data\n");
|
|
886
|
+
return;
|
|
887
|
+
}
|
|
888
|
+
printKv({ instId: r["instId"], maxBuy: r["maxBuy"], maxSell: r["maxSell"] });
|
|
889
|
+
}
|
|
890
|
+
async function cmdAccountMaxAvailSize(client, opts) {
|
|
891
|
+
const res = await client.privateGet("/api/v5/account/max-avail-size", {
|
|
892
|
+
instId: opts.instId,
|
|
893
|
+
tdMode: opts.tdMode
|
|
894
|
+
});
|
|
895
|
+
const data = res.data;
|
|
896
|
+
if (opts.json) return printJson(data);
|
|
897
|
+
const r = data?.[0];
|
|
898
|
+
if (!r) {
|
|
899
|
+
process.stdout.write("No data\n");
|
|
900
|
+
return;
|
|
901
|
+
}
|
|
902
|
+
printKv({ instId: r["instId"], availBuy: r["availBuy"], availSell: r["availSell"] });
|
|
903
|
+
}
|
|
904
|
+
async function cmdAccountMaxWithdrawal(client, ccy, json) {
|
|
905
|
+
const params = {};
|
|
906
|
+
if (ccy) params["ccy"] = ccy;
|
|
907
|
+
const res = await client.privateGet("/api/v5/account/max-withdrawal", params);
|
|
908
|
+
const data = res.data;
|
|
909
|
+
if (json) return printJson(data);
|
|
910
|
+
printTable(
|
|
911
|
+
(data ?? []).map((r) => ({
|
|
912
|
+
ccy: r["ccy"],
|
|
913
|
+
maxWd: r["maxWd"],
|
|
914
|
+
maxWdEx: r["maxWdEx"]
|
|
915
|
+
}))
|
|
916
|
+
);
|
|
917
|
+
}
|
|
918
|
+
async function cmdAccountPositionsHistory(client, opts) {
|
|
919
|
+
const params = {};
|
|
920
|
+
if (opts.instType) params["instType"] = opts.instType;
|
|
921
|
+
if (opts.instId) params["instId"] = opts.instId;
|
|
922
|
+
if (opts.limit) params["limit"] = String(opts.limit);
|
|
923
|
+
const res = await client.privateGet("/api/v5/account/positions-history", params);
|
|
924
|
+
const data = res.data;
|
|
925
|
+
if (opts.json) return printJson(data);
|
|
926
|
+
printTable(
|
|
927
|
+
(data ?? []).map((p) => ({
|
|
928
|
+
instId: p["instId"],
|
|
929
|
+
direction: p["direction"],
|
|
930
|
+
openAvgPx: p["openAvgPx"],
|
|
931
|
+
closeAvgPx: p["closeAvgPx"],
|
|
932
|
+
realizedPnl: p["realizedPnl"],
|
|
933
|
+
uTime: new Date(Number(p["uTime"])).toLocaleString()
|
|
934
|
+
}))
|
|
935
|
+
);
|
|
936
|
+
}
|
|
937
|
+
async function cmdAccountTransfer(client, opts) {
|
|
938
|
+
const body = {
|
|
939
|
+
ccy: opts.ccy,
|
|
940
|
+
amt: opts.amt,
|
|
941
|
+
from: opts.from,
|
|
942
|
+
to: opts.to
|
|
943
|
+
};
|
|
944
|
+
if (opts.transferType) body["type"] = opts.transferType;
|
|
945
|
+
if (opts.subAcct) body["subAcct"] = opts.subAcct;
|
|
946
|
+
const res = await client.privatePost("/api/v5/asset/transfer", body);
|
|
947
|
+
if (opts.json) return printJson(res.data);
|
|
948
|
+
const r = res.data[0];
|
|
949
|
+
process.stdout.write(`Transfer: ${r?.["transId"]} (${r?.["ccy"]} ${r?.["amt"]})
|
|
950
|
+
`);
|
|
951
|
+
}
|
|
603
952
|
|
|
604
953
|
// src/commands/spot.ts
|
|
605
954
|
async function cmdSpotOrders(client, opts) {
|
|
@@ -693,6 +1042,43 @@ async function cmdSpotAlgoCancel(client, instId, algoId, json) {
|
|
|
693
1042
|
`
|
|
694
1043
|
);
|
|
695
1044
|
}
|
|
1045
|
+
async function cmdSpotGet(client, opts) {
|
|
1046
|
+
const params = { instId: opts.instId };
|
|
1047
|
+
if (opts.ordId) params["ordId"] = opts.ordId;
|
|
1048
|
+
if (opts.clOrdId) params["clOrdId"] = opts.clOrdId;
|
|
1049
|
+
const res = await client.privateGet("/api/v5/trade/order", params);
|
|
1050
|
+
const data = res.data;
|
|
1051
|
+
if (opts.json) return printJson(data);
|
|
1052
|
+
const o = data?.[0];
|
|
1053
|
+
if (!o) {
|
|
1054
|
+
process.stdout.write("No data\n");
|
|
1055
|
+
return;
|
|
1056
|
+
}
|
|
1057
|
+
printKv({
|
|
1058
|
+
ordId: o["ordId"],
|
|
1059
|
+
instId: o["instId"],
|
|
1060
|
+
side: o["side"],
|
|
1061
|
+
ordType: o["ordType"],
|
|
1062
|
+
px: o["px"],
|
|
1063
|
+
sz: o["sz"],
|
|
1064
|
+
fillSz: o["fillSz"],
|
|
1065
|
+
avgPx: o["avgPx"],
|
|
1066
|
+
state: o["state"],
|
|
1067
|
+
cTime: new Date(Number(o["cTime"])).toLocaleString()
|
|
1068
|
+
});
|
|
1069
|
+
}
|
|
1070
|
+
async function cmdSpotAmend(client, opts) {
|
|
1071
|
+
const body = { instId: opts.instId };
|
|
1072
|
+
if (opts.ordId) body["ordId"] = opts.ordId;
|
|
1073
|
+
if (opts.clOrdId) body["clOrdId"] = opts.clOrdId;
|
|
1074
|
+
if (opts.newSz) body["newSz"] = opts.newSz;
|
|
1075
|
+
if (opts.newPx) body["newPx"] = opts.newPx;
|
|
1076
|
+
const res = await client.privatePost("/api/v5/trade/amend-order", body);
|
|
1077
|
+
if (opts.json) return printJson(res.data);
|
|
1078
|
+
const r = res.data[0];
|
|
1079
|
+
process.stdout.write(`Order amended: ${r?.["ordId"]} (${r?.["sCode"] === "0" ? "OK" : r?.["sMsg"]})
|
|
1080
|
+
`);
|
|
1081
|
+
}
|
|
696
1082
|
async function cmdSpotAlgoOrders(client, opts) {
|
|
697
1083
|
const endpoint = opts.status === "history" ? "/api/v5/trade/orders-algo-history" : "/api/v5/trade/orders-algo-pending";
|
|
698
1084
|
const baseParams = { instType: "SPOT" };
|
|
@@ -925,6 +1311,80 @@ async function cmdSwapAlgoOrders(client, opts) {
|
|
|
925
1311
|
}))
|
|
926
1312
|
);
|
|
927
1313
|
}
|
|
1314
|
+
async function cmdSwapFills(client, opts) {
|
|
1315
|
+
const path3 = opts.archive ? "/api/v5/trade/fills-history" : "/api/v5/trade/fills";
|
|
1316
|
+
const params = { instType: "SWAP" };
|
|
1317
|
+
if (opts.instId) params["instId"] = opts.instId;
|
|
1318
|
+
if (opts.ordId) params["ordId"] = opts.ordId;
|
|
1319
|
+
const res = await client.privateGet(path3, params);
|
|
1320
|
+
const fills = res.data;
|
|
1321
|
+
if (opts.json) return printJson(fills);
|
|
1322
|
+
printTable(
|
|
1323
|
+
(fills ?? []).map((f) => ({
|
|
1324
|
+
instId: f["instId"],
|
|
1325
|
+
side: f["side"],
|
|
1326
|
+
fillPx: f["fillPx"],
|
|
1327
|
+
fillSz: f["fillSz"],
|
|
1328
|
+
fee: f["fee"],
|
|
1329
|
+
ts: new Date(Number(f["ts"])).toLocaleString()
|
|
1330
|
+
}))
|
|
1331
|
+
);
|
|
1332
|
+
}
|
|
1333
|
+
async function cmdSwapGet(client, opts) {
|
|
1334
|
+
const params = { instId: opts.instId };
|
|
1335
|
+
if (opts.ordId) params["ordId"] = opts.ordId;
|
|
1336
|
+
if (opts.clOrdId) params["clOrdId"] = opts.clOrdId;
|
|
1337
|
+
const res = await client.privateGet("/api/v5/trade/order", params);
|
|
1338
|
+
const data = res.data;
|
|
1339
|
+
if (opts.json) return printJson(data);
|
|
1340
|
+
const o = data?.[0];
|
|
1341
|
+
if (!o) {
|
|
1342
|
+
process.stdout.write("No data\n");
|
|
1343
|
+
return;
|
|
1344
|
+
}
|
|
1345
|
+
printKv({
|
|
1346
|
+
ordId: o["ordId"],
|
|
1347
|
+
instId: o["instId"],
|
|
1348
|
+
side: o["side"],
|
|
1349
|
+
posSide: o["posSide"],
|
|
1350
|
+
ordType: o["ordType"],
|
|
1351
|
+
px: o["px"],
|
|
1352
|
+
sz: o["sz"],
|
|
1353
|
+
fillSz: o["fillSz"],
|
|
1354
|
+
avgPx: o["avgPx"],
|
|
1355
|
+
state: o["state"],
|
|
1356
|
+
cTime: new Date(Number(o["cTime"])).toLocaleString()
|
|
1357
|
+
});
|
|
1358
|
+
}
|
|
1359
|
+
async function cmdSwapClose(client, opts) {
|
|
1360
|
+
const body = {
|
|
1361
|
+
instId: opts.instId,
|
|
1362
|
+
mgnMode: opts.mgnMode
|
|
1363
|
+
};
|
|
1364
|
+
if (opts.posSide) body["posSide"] = opts.posSide;
|
|
1365
|
+
if (opts.autoCxl !== void 0) body["autoCxl"] = String(opts.autoCxl);
|
|
1366
|
+
const res = await client.privatePost("/api/v5/trade/close-position", body);
|
|
1367
|
+
if (opts.json) return printJson(res.data);
|
|
1368
|
+
const r = res.data[0];
|
|
1369
|
+
process.stdout.write(`Position closed: ${r?.["instId"]} ${r?.["posSide"] ?? ""}
|
|
1370
|
+
`);
|
|
1371
|
+
}
|
|
1372
|
+
async function cmdSwapGetLeverage(client, opts) {
|
|
1373
|
+
const res = await client.privateGet("/api/v5/account/leverage-info", {
|
|
1374
|
+
instId: opts.instId,
|
|
1375
|
+
mgnMode: opts.mgnMode
|
|
1376
|
+
});
|
|
1377
|
+
const data = res.data;
|
|
1378
|
+
if (opts.json) return printJson(data);
|
|
1379
|
+
printTable(
|
|
1380
|
+
(data ?? []).map((r) => ({
|
|
1381
|
+
instId: r["instId"],
|
|
1382
|
+
mgnMode: r["mgnMode"],
|
|
1383
|
+
posSide: r["posSide"],
|
|
1384
|
+
lever: r["lever"]
|
|
1385
|
+
}))
|
|
1386
|
+
);
|
|
1387
|
+
}
|
|
928
1388
|
async function cmdSwapSetLeverage(client, opts) {
|
|
929
1389
|
const body = {
|
|
930
1390
|
instId: opts.instId,
|
|
@@ -939,6 +1399,118 @@ async function cmdSwapSetLeverage(client, opts) {
|
|
|
939
1399
|
`);
|
|
940
1400
|
}
|
|
941
1401
|
|
|
1402
|
+
// src/commands/futures.ts
|
|
1403
|
+
async function cmdFuturesOrders(client, opts) {
|
|
1404
|
+
const path3 = opts.status === "archive" ? "/api/v5/trade/orders-history-archive" : opts.status === "history" ? "/api/v5/trade/orders-history" : "/api/v5/trade/orders-pending";
|
|
1405
|
+
const params = { instType: "FUTURES" };
|
|
1406
|
+
if (opts.instId) params["instId"] = opts.instId;
|
|
1407
|
+
const res = await client.privateGet(path3, params);
|
|
1408
|
+
const orders = res.data;
|
|
1409
|
+
if (opts.json) return printJson(orders);
|
|
1410
|
+
printTable(
|
|
1411
|
+
(orders ?? []).map((o) => ({
|
|
1412
|
+
ordId: o["ordId"],
|
|
1413
|
+
instId: o["instId"],
|
|
1414
|
+
side: o["side"],
|
|
1415
|
+
posSide: o["posSide"],
|
|
1416
|
+
type: o["ordType"],
|
|
1417
|
+
price: o["px"],
|
|
1418
|
+
size: o["sz"],
|
|
1419
|
+
state: o["state"]
|
|
1420
|
+
}))
|
|
1421
|
+
);
|
|
1422
|
+
}
|
|
1423
|
+
async function cmdFuturesPositions(client, instId, json) {
|
|
1424
|
+
const params = { instType: "FUTURES" };
|
|
1425
|
+
if (instId) params["instId"] = instId;
|
|
1426
|
+
const res = await client.privateGet("/api/v5/account/positions", params);
|
|
1427
|
+
const positions = res.data;
|
|
1428
|
+
if (json) return printJson(positions);
|
|
1429
|
+
const open = (positions ?? []).filter((p) => Number(p["pos"]) !== 0);
|
|
1430
|
+
if (!open.length) {
|
|
1431
|
+
process.stdout.write("No open positions\n");
|
|
1432
|
+
return;
|
|
1433
|
+
}
|
|
1434
|
+
printTable(
|
|
1435
|
+
open.map((p) => ({
|
|
1436
|
+
instId: p["instId"],
|
|
1437
|
+
side: p["posSide"],
|
|
1438
|
+
pos: p["pos"],
|
|
1439
|
+
avgPx: p["avgPx"],
|
|
1440
|
+
upl: p["upl"],
|
|
1441
|
+
lever: p["lever"]
|
|
1442
|
+
}))
|
|
1443
|
+
);
|
|
1444
|
+
}
|
|
1445
|
+
async function cmdFuturesFills(client, opts) {
|
|
1446
|
+
const path3 = opts.archive ? "/api/v5/trade/fills-history" : "/api/v5/trade/fills";
|
|
1447
|
+
const params = { instType: "FUTURES" };
|
|
1448
|
+
if (opts.instId) params["instId"] = opts.instId;
|
|
1449
|
+
if (opts.ordId) params["ordId"] = opts.ordId;
|
|
1450
|
+
const res = await client.privateGet(path3, params);
|
|
1451
|
+
const fills = res.data;
|
|
1452
|
+
if (opts.json) return printJson(fills);
|
|
1453
|
+
printTable(
|
|
1454
|
+
(fills ?? []).map((f) => ({
|
|
1455
|
+
instId: f["instId"],
|
|
1456
|
+
side: f["side"],
|
|
1457
|
+
fillPx: f["fillPx"],
|
|
1458
|
+
fillSz: f["fillSz"],
|
|
1459
|
+
fee: f["fee"],
|
|
1460
|
+
ts: new Date(Number(f["ts"])).toLocaleString()
|
|
1461
|
+
}))
|
|
1462
|
+
);
|
|
1463
|
+
}
|
|
1464
|
+
async function cmdFuturesPlace(client, opts) {
|
|
1465
|
+
const body = {
|
|
1466
|
+
instId: opts.instId,
|
|
1467
|
+
tdMode: opts.tdMode,
|
|
1468
|
+
side: opts.side,
|
|
1469
|
+
ordType: opts.ordType,
|
|
1470
|
+
sz: opts.sz
|
|
1471
|
+
};
|
|
1472
|
+
if (opts.posSide) body["posSide"] = opts.posSide;
|
|
1473
|
+
if (opts.px) body["px"] = opts.px;
|
|
1474
|
+
if (opts.reduceOnly !== void 0) body["reduceOnly"] = String(opts.reduceOnly);
|
|
1475
|
+
const res = await client.privatePost("/api/v5/trade/order", body);
|
|
1476
|
+
if (opts.json) return printJson(res.data);
|
|
1477
|
+
const order = res.data[0];
|
|
1478
|
+
process.stdout.write(`Order placed: ${order?.["ordId"]} (${order?.["sCode"] === "0" ? "OK" : order?.["sMsg"]})
|
|
1479
|
+
`);
|
|
1480
|
+
}
|
|
1481
|
+
async function cmdFuturesCancel(client, instId, ordId, json) {
|
|
1482
|
+
const res = await client.privatePost("/api/v5/trade/cancel-order", { instId, ordId });
|
|
1483
|
+
if (json) return printJson(res.data);
|
|
1484
|
+
const r = res.data[0];
|
|
1485
|
+
process.stdout.write(`Cancelled: ${r?.["ordId"]} (${r?.["sCode"] === "0" ? "OK" : r?.["sMsg"]})
|
|
1486
|
+
`);
|
|
1487
|
+
}
|
|
1488
|
+
async function cmdFuturesGet(client, opts) {
|
|
1489
|
+
const params = { instId: opts.instId };
|
|
1490
|
+
if (opts.ordId) params["ordId"] = opts.ordId;
|
|
1491
|
+
const res = await client.privateGet("/api/v5/trade/order", params);
|
|
1492
|
+
const data = res.data;
|
|
1493
|
+
if (opts.json) return printJson(data);
|
|
1494
|
+
const o = data?.[0];
|
|
1495
|
+
if (!o) {
|
|
1496
|
+
process.stdout.write("No data\n");
|
|
1497
|
+
return;
|
|
1498
|
+
}
|
|
1499
|
+
printKv({
|
|
1500
|
+
ordId: o["ordId"],
|
|
1501
|
+
instId: o["instId"],
|
|
1502
|
+
side: o["side"],
|
|
1503
|
+
posSide: o["posSide"],
|
|
1504
|
+
ordType: o["ordType"],
|
|
1505
|
+
px: o["px"],
|
|
1506
|
+
sz: o["sz"],
|
|
1507
|
+
fillSz: o["fillSz"],
|
|
1508
|
+
avgPx: o["avgPx"],
|
|
1509
|
+
state: o["state"],
|
|
1510
|
+
cTime: new Date(Number(o["cTime"])).toLocaleString()
|
|
1511
|
+
});
|
|
1512
|
+
}
|
|
1513
|
+
|
|
942
1514
|
// src/config/toml.ts
|
|
943
1515
|
import { writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, existsSync as existsSync3 } from "fs";
|
|
944
1516
|
import { stringify } from "smol-toml";
|
|
@@ -955,13 +1527,18 @@ function writeCliConfig(config) {
|
|
|
955
1527
|
|
|
956
1528
|
// src/commands/config.ts
|
|
957
1529
|
import { existsSync as existsSync4, readFileSync as readFileSync3 } from "fs";
|
|
958
|
-
import { parse as parse2 } from "smol-toml";
|
|
1530
|
+
import { parse as parse2, stringify as stringify2 } from "smol-toml";
|
|
1531
|
+
import { createInterface } from "readline";
|
|
1532
|
+
import { spawnSync } from "child_process";
|
|
959
1533
|
function readFullConfig() {
|
|
960
|
-
const
|
|
961
|
-
if (!existsSync4(
|
|
962
|
-
const raw = readFileSync3(
|
|
1534
|
+
const path3 = configFilePath();
|
|
1535
|
+
if (!existsSync4(path3)) return { profiles: {} };
|
|
1536
|
+
const raw = readFileSync3(path3, "utf-8");
|
|
963
1537
|
return parse2(raw);
|
|
964
1538
|
}
|
|
1539
|
+
function prompt(rl, question) {
|
|
1540
|
+
return new Promise((resolve) => rl.question(question, resolve));
|
|
1541
|
+
}
|
|
965
1542
|
function cmdConfigShow(json) {
|
|
966
1543
|
const config = readFullConfig();
|
|
967
1544
|
if (json) return printJson(config);
|
|
@@ -995,6 +1572,301 @@ function cmdConfigSet(key, value) {
|
|
|
995
1572
|
process.exitCode = 1;
|
|
996
1573
|
}
|
|
997
1574
|
}
|
|
1575
|
+
async function cmdConfigInit() {
|
|
1576
|
+
const apiUrl = "https://www.okx.com/account/my-api";
|
|
1577
|
+
process.stdout.write("OKX Trade CLI \u2014 \u914D\u7F6E\u5411\u5BFC\n\n");
|
|
1578
|
+
process.stdout.write(`\u8BF7\u524D\u5F80 ${apiUrl} \u521B\u5EFA API Key\uFF08\u9700\u8981 trade \u6743\u9650\uFF09
|
|
1579
|
+
|
|
1580
|
+
`);
|
|
1581
|
+
try {
|
|
1582
|
+
const opener = process.platform === "darwin" ? "open" : "xdg-open";
|
|
1583
|
+
spawnSync(opener, [apiUrl], { stdio: "ignore" });
|
|
1584
|
+
} catch {
|
|
1585
|
+
}
|
|
1586
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
1587
|
+
try {
|
|
1588
|
+
const profileNameRaw = await prompt(rl, "Profile \u540D\u79F0 (\u9ED8\u8BA4: default): ");
|
|
1589
|
+
const profileName = profileNameRaw.trim() || "default";
|
|
1590
|
+
const apiKey = (await prompt(rl, "API Key: ")).trim();
|
|
1591
|
+
if (!apiKey) {
|
|
1592
|
+
process.stderr.write("\u9519\u8BEF: API Key \u4E0D\u80FD\u4E3A\u7A7A\n");
|
|
1593
|
+
process.exitCode = 1;
|
|
1594
|
+
return;
|
|
1595
|
+
}
|
|
1596
|
+
const secretKey = (await prompt(rl, "Secret Key: ")).trim();
|
|
1597
|
+
if (!secretKey) {
|
|
1598
|
+
process.stderr.write("\u9519\u8BEF: Secret Key \u4E0D\u80FD\u4E3A\u7A7A\n");
|
|
1599
|
+
process.exitCode = 1;
|
|
1600
|
+
return;
|
|
1601
|
+
}
|
|
1602
|
+
const passphrase = (await prompt(rl, "Passphrase: ")).trim();
|
|
1603
|
+
if (!passphrase) {
|
|
1604
|
+
process.stderr.write("\u9519\u8BEF: Passphrase \u4E0D\u80FD\u4E3A\u7A7A\n");
|
|
1605
|
+
process.exitCode = 1;
|
|
1606
|
+
return;
|
|
1607
|
+
}
|
|
1608
|
+
const demoRaw = (await prompt(rl, "\u4F7F\u7528\u6A21\u62DF\u76D8\uFF1F(Y/n) ")).trim().toLowerCase();
|
|
1609
|
+
const demo = demoRaw !== "n";
|
|
1610
|
+
if (demo) {
|
|
1611
|
+
process.stdout.write("\u5DF2\u9009\u62E9\u6A21\u62DF\u76D8\u6A21\u5F0F\uFF0C\u53EF\u968F\u65F6\u901A\u8FC7 okx config set \u5207\u6362\u4E3A\u5B9E\u76D8\u3002\n");
|
|
1612
|
+
}
|
|
1613
|
+
const config = readFullConfig();
|
|
1614
|
+
config.profiles[profileName] = { api_key: apiKey, secret_key: secretKey, passphrase, demo };
|
|
1615
|
+
const configPath = configFilePath();
|
|
1616
|
+
try {
|
|
1617
|
+
writeCliConfig(config);
|
|
1618
|
+
process.stdout.write(`
|
|
1619
|
+
\u914D\u7F6E\u5DF2\u4FDD\u5B58\u5230 ${configPath}
|
|
1620
|
+
`);
|
|
1621
|
+
process.stdout.write(`\u4F7F\u7528\u65B9\u5F0F: okx --profile ${profileName} account balance
|
|
1622
|
+
`);
|
|
1623
|
+
if (!config.default_profile) {
|
|
1624
|
+
process.stdout.write(`\u63D0\u793A: \u8FD0\u884C okx config set default_profile ${profileName} \u53EF\u5C06\u5176\u8BBE\u4E3A\u9ED8\u8BA4
|
|
1625
|
+
`);
|
|
1626
|
+
}
|
|
1627
|
+
} catch (err) {
|
|
1628
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1629
|
+
const isPermission = err instanceof Error && "code" in err && (err.code === "EACCES" || err.code === "EPERM");
|
|
1630
|
+
process.stderr.write(`\u5199\u5165\u914D\u7F6E\u6587\u4EF6\u5931\u8D25: ${message}
|
|
1631
|
+
`);
|
|
1632
|
+
if (isPermission) {
|
|
1633
|
+
process.stderr.write(`\u6743\u9650\u4E0D\u8DB3\uFF0C\u8BF7\u68C0\u67E5 ${configPath} \u53CA\u5176\u7236\u76EE\u5F55\u7684\u8BFB\u5199\u6743\u9650\u3002
|
|
1634
|
+
`);
|
|
1635
|
+
}
|
|
1636
|
+
process.stderr.write("\u8BF7\u624B\u52A8\u5C06\u4EE5\u4E0B\u5185\u5BB9\u5199\u5165 " + configPath + ":\n\n");
|
|
1637
|
+
process.stdout.write(stringify2(config) + "\n");
|
|
1638
|
+
process.exitCode = 1;
|
|
1639
|
+
}
|
|
1640
|
+
} finally {
|
|
1641
|
+
rl.close();
|
|
1642
|
+
}
|
|
1643
|
+
}
|
|
1644
|
+
|
|
1645
|
+
// src/commands/client-setup.ts
|
|
1646
|
+
import * as fs from "fs";
|
|
1647
|
+
import * as path2 from "path";
|
|
1648
|
+
import * as os2 from "os";
|
|
1649
|
+
import * as readline from "readline";
|
|
1650
|
+
var CLIENTS = [
|
|
1651
|
+
{
|
|
1652
|
+
name: "Claude Desktop",
|
|
1653
|
+
configPath: path2.join(os2.homedir(), "Library/Application Support/Claude/claude_desktop_config.json"),
|
|
1654
|
+
mcpKey: "mcpServers"
|
|
1655
|
+
},
|
|
1656
|
+
{
|
|
1657
|
+
name: "Cursor",
|
|
1658
|
+
configPath: path2.join(os2.homedir(), ".cursor/mcp.json"),
|
|
1659
|
+
mcpKey: "mcpServers"
|
|
1660
|
+
},
|
|
1661
|
+
{
|
|
1662
|
+
name: "Windsurf",
|
|
1663
|
+
configPath: path2.join(os2.homedir(), ".codeium/windsurf/mcp_config.json"),
|
|
1664
|
+
mcpKey: "mcpServers"
|
|
1665
|
+
}
|
|
1666
|
+
];
|
|
1667
|
+
var MCP_ENTRY = {
|
|
1668
|
+
command: "okx-trade-mcp",
|
|
1669
|
+
args: ["--modules", "all"]
|
|
1670
|
+
};
|
|
1671
|
+
var MCP_SERVER_NAME = "okx-trade-mcp";
|
|
1672
|
+
function prompt2(rl, question) {
|
|
1673
|
+
return new Promise((resolve) => {
|
|
1674
|
+
rl.question(question, (answer) => {
|
|
1675
|
+
resolve(answer);
|
|
1676
|
+
});
|
|
1677
|
+
});
|
|
1678
|
+
}
|
|
1679
|
+
async function cmdSetupClients() {
|
|
1680
|
+
const detected = CLIENTS.filter((c) => fs.existsSync(c.configPath));
|
|
1681
|
+
if (detected.length === 0) {
|
|
1682
|
+
process.stdout.write(
|
|
1683
|
+
"No supported IDE/client installations detected.\nChecked:\n" + CLIENTS.map((c) => ` - ${c.name}: ${c.configPath}`).join("\n") + "\n"
|
|
1684
|
+
);
|
|
1685
|
+
return;
|
|
1686
|
+
}
|
|
1687
|
+
process.stdout.write(`Detected ${detected.length} client(s):
|
|
1688
|
+
`);
|
|
1689
|
+
for (const c of detected) {
|
|
1690
|
+
process.stdout.write(` - ${c.name}
|
|
1691
|
+
`);
|
|
1692
|
+
}
|
|
1693
|
+
process.stdout.write("\n");
|
|
1694
|
+
const rl = readline.createInterface({
|
|
1695
|
+
input: process.stdin,
|
|
1696
|
+
output: process.stdout
|
|
1697
|
+
});
|
|
1698
|
+
try {
|
|
1699
|
+
for (const client of detected) {
|
|
1700
|
+
const answer = await prompt2(rl, `Configure ${client.name}? (y/N) `);
|
|
1701
|
+
if (answer.trim().toLowerCase() !== "y") {
|
|
1702
|
+
process.stdout.write(` Skipped ${client.name}.
|
|
1703
|
+
`);
|
|
1704
|
+
continue;
|
|
1705
|
+
}
|
|
1706
|
+
let data = { [client.mcpKey]: {} };
|
|
1707
|
+
if (fs.existsSync(client.configPath)) {
|
|
1708
|
+
const raw = fs.readFileSync(client.configPath, "utf-8");
|
|
1709
|
+
try {
|
|
1710
|
+
data = JSON.parse(raw);
|
|
1711
|
+
} catch {
|
|
1712
|
+
process.stderr.write(
|
|
1713
|
+
` Error: Failed to parse JSON for ${client.name} at ${client.configPath}. Skipping.
|
|
1714
|
+
`
|
|
1715
|
+
);
|
|
1716
|
+
continue;
|
|
1717
|
+
}
|
|
1718
|
+
}
|
|
1719
|
+
if (typeof data[client.mcpKey] !== "object" || data[client.mcpKey] === null) {
|
|
1720
|
+
data[client.mcpKey] = {};
|
|
1721
|
+
}
|
|
1722
|
+
const servers = data[client.mcpKey];
|
|
1723
|
+
if (Object.prototype.hasOwnProperty.call(servers, MCP_SERVER_NAME)) {
|
|
1724
|
+
process.stdout.write(` Already configured in ${client.name}. Skipping.
|
|
1725
|
+
`);
|
|
1726
|
+
continue;
|
|
1727
|
+
}
|
|
1728
|
+
servers[MCP_SERVER_NAME] = MCP_ENTRY;
|
|
1729
|
+
const jsonOutput = JSON.stringify(data, null, 2);
|
|
1730
|
+
try {
|
|
1731
|
+
fs.writeFileSync(client.configPath, jsonOutput, "utf-8");
|
|
1732
|
+
process.stdout.write(` Configured ${client.name} successfully.
|
|
1733
|
+
`);
|
|
1734
|
+
} catch (err) {
|
|
1735
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
1736
|
+
process.stderr.write(
|
|
1737
|
+
` Error: Failed to write config for ${client.name}: ${reason}
|
|
1738
|
+
Add the following to "${client.configPath}" manually:
|
|
1739
|
+
|
|
1740
|
+
"${MCP_SERVER_NAME}": ${JSON.stringify(MCP_ENTRY, null, 2).split("\n").join("\n ")}
|
|
1741
|
+
|
|
1742
|
+
`
|
|
1743
|
+
);
|
|
1744
|
+
}
|
|
1745
|
+
}
|
|
1746
|
+
} finally {
|
|
1747
|
+
rl.close();
|
|
1748
|
+
}
|
|
1749
|
+
process.stdout.write(
|
|
1750
|
+
"\nDone. Please restart any configured IDE/client for the changes to take effect.\n"
|
|
1751
|
+
);
|
|
1752
|
+
}
|
|
1753
|
+
|
|
1754
|
+
// src/commands/bot.ts
|
|
1755
|
+
async function cmdGridOrders(client, opts) {
|
|
1756
|
+
const path3 = opts.status === "history" ? "/api/v5/tradingBot/grid/orders-algo-history" : "/api/v5/tradingBot/grid/orders-algo-pending";
|
|
1757
|
+
const params = { algoOrdType: opts.algoOrdType };
|
|
1758
|
+
if (opts.instId) params["instId"] = opts.instId;
|
|
1759
|
+
if (opts.algoId) params["algoId"] = opts.algoId;
|
|
1760
|
+
const res = await client.privateGet(path3, params);
|
|
1761
|
+
const orders = res.data ?? [];
|
|
1762
|
+
if (opts.json) return printJson(orders);
|
|
1763
|
+
if (!orders.length) {
|
|
1764
|
+
process.stdout.write("No grid bots\n");
|
|
1765
|
+
return;
|
|
1766
|
+
}
|
|
1767
|
+
printTable(
|
|
1768
|
+
orders.map((o) => ({
|
|
1769
|
+
algoId: o["algoId"],
|
|
1770
|
+
instId: o["instId"],
|
|
1771
|
+
type: o["algoOrdType"],
|
|
1772
|
+
state: o["state"],
|
|
1773
|
+
pnl: o["pnlRatio"],
|
|
1774
|
+
gridNum: o["gridNum"],
|
|
1775
|
+
maxPx: o["maxPx"],
|
|
1776
|
+
minPx: o["minPx"],
|
|
1777
|
+
createdAt: new Date(Number(o["cTime"])).toLocaleString()
|
|
1778
|
+
}))
|
|
1779
|
+
);
|
|
1780
|
+
}
|
|
1781
|
+
async function cmdGridDetails(client, opts) {
|
|
1782
|
+
const res = await client.privateGet("/api/v5/tradingBot/grid/orders-algo-details", {
|
|
1783
|
+
algoOrdType: opts.algoOrdType,
|
|
1784
|
+
algoId: opts.algoId
|
|
1785
|
+
});
|
|
1786
|
+
const detail = (res.data ?? [])[0];
|
|
1787
|
+
if (!detail) {
|
|
1788
|
+
process.stdout.write("Bot not found\n");
|
|
1789
|
+
return;
|
|
1790
|
+
}
|
|
1791
|
+
if (opts.json) return printJson(detail);
|
|
1792
|
+
printKv({
|
|
1793
|
+
algoId: detail["algoId"],
|
|
1794
|
+
instId: detail["instId"],
|
|
1795
|
+
type: detail["algoOrdType"],
|
|
1796
|
+
state: detail["state"],
|
|
1797
|
+
maxPx: detail["maxPx"],
|
|
1798
|
+
minPx: detail["minPx"],
|
|
1799
|
+
gridNum: detail["gridNum"],
|
|
1800
|
+
runType: detail["runType"] === "1" ? "arithmetic" : "geometric",
|
|
1801
|
+
pnl: detail["pnl"],
|
|
1802
|
+
pnlRatio: detail["pnlRatio"],
|
|
1803
|
+
investAmt: detail["investAmt"],
|
|
1804
|
+
totalAnnRate: detail["totalAnnRate"],
|
|
1805
|
+
createdAt: new Date(Number(detail["cTime"])).toLocaleString()
|
|
1806
|
+
});
|
|
1807
|
+
}
|
|
1808
|
+
async function cmdGridSubOrders(client, opts) {
|
|
1809
|
+
const res = await client.privateGet("/api/v5/tradingBot/grid/sub-orders", {
|
|
1810
|
+
algoOrdType: opts.algoOrdType,
|
|
1811
|
+
algoId: opts.algoId,
|
|
1812
|
+
type: opts.type
|
|
1813
|
+
});
|
|
1814
|
+
const orders = res.data ?? [];
|
|
1815
|
+
if (opts.json) return printJson(orders);
|
|
1816
|
+
if (!orders.length) {
|
|
1817
|
+
process.stdout.write("No sub-orders\n");
|
|
1818
|
+
return;
|
|
1819
|
+
}
|
|
1820
|
+
printTable(
|
|
1821
|
+
orders.map((o) => ({
|
|
1822
|
+
ordId: o["ordId"],
|
|
1823
|
+
side: o["side"],
|
|
1824
|
+
px: o["px"],
|
|
1825
|
+
sz: o["sz"],
|
|
1826
|
+
fillPx: o["fillPx"],
|
|
1827
|
+
fillSz: o["fillSz"],
|
|
1828
|
+
state: o["state"],
|
|
1829
|
+
fee: o["fee"]
|
|
1830
|
+
}))
|
|
1831
|
+
);
|
|
1832
|
+
}
|
|
1833
|
+
async function cmdGridCreate(client, opts) {
|
|
1834
|
+
const body = {
|
|
1835
|
+
instId: opts.instId,
|
|
1836
|
+
algoOrdType: opts.algoOrdType,
|
|
1837
|
+
maxPx: opts.maxPx,
|
|
1838
|
+
minPx: opts.minPx,
|
|
1839
|
+
gridNum: opts.gridNum
|
|
1840
|
+
};
|
|
1841
|
+
if (opts.runType) body["runType"] = opts.runType;
|
|
1842
|
+
if (opts.quoteSz) body["quoteSz"] = opts.quoteSz;
|
|
1843
|
+
if (opts.baseSz) body["baseSz"] = opts.baseSz;
|
|
1844
|
+
if (opts.direction) body["direction"] = opts.direction;
|
|
1845
|
+
if (opts.lever) body["lever"] = opts.lever;
|
|
1846
|
+
if (opts.sz) body["sz"] = opts.sz;
|
|
1847
|
+
const res = await client.privatePost("/api/v5/tradingBot/grid/order-algo", body);
|
|
1848
|
+
if (opts.json) return printJson(res.data);
|
|
1849
|
+
const r = res.data[0];
|
|
1850
|
+
process.stdout.write(
|
|
1851
|
+
`Grid bot created: ${r?.["algoId"]} (${r?.["sCode"] === "0" ? "OK" : r?.["sMsg"]})
|
|
1852
|
+
`
|
|
1853
|
+
);
|
|
1854
|
+
}
|
|
1855
|
+
async function cmdGridStop(client, opts) {
|
|
1856
|
+
const entry = {
|
|
1857
|
+
algoId: opts.algoId,
|
|
1858
|
+
algoOrdType: opts.algoOrdType,
|
|
1859
|
+
instId: opts.instId
|
|
1860
|
+
};
|
|
1861
|
+
if (opts.stopType) entry["stopType"] = opts.stopType;
|
|
1862
|
+
const res = await client.privatePost("/api/v5/tradingBot/grid/stop-order-algo", [entry]);
|
|
1863
|
+
if (opts.json) return printJson(res.data);
|
|
1864
|
+
const r = res.data[0];
|
|
1865
|
+
process.stdout.write(
|
|
1866
|
+
`Grid bot stopped: ${r?.["algoId"]} (${r?.["sCode"] === "0" ? "OK" : r?.["sMsg"]})
|
|
1867
|
+
`
|
|
1868
|
+
);
|
|
1869
|
+
}
|
|
998
1870
|
|
|
999
1871
|
// src/index.ts
|
|
1000
1872
|
var _require = createRequire(import.meta.url);
|
|
@@ -1005,6 +1877,7 @@ Usage: okx [--profile <name>] [--json] <command> [args]
|
|
|
1005
1877
|
|
|
1006
1878
|
Global Options:
|
|
1007
1879
|
--profile <name> Use a named profile from ~/.okx/config.toml
|
|
1880
|
+
--demo Use simulated trading (demo) mode
|
|
1008
1881
|
--json Output raw JSON
|
|
1009
1882
|
--help Show this help
|
|
1010
1883
|
|
|
@@ -1013,12 +1886,33 @@ Commands:
|
|
|
1013
1886
|
market tickers <instType> (SPOT|SWAP|FUTURES|OPTION)
|
|
1014
1887
|
market orderbook <instId> [--sz <n>]
|
|
1015
1888
|
market candles <instId> [--bar <bar>] [--limit <n>]
|
|
1889
|
+
market instruments --instType <type> [--instId <id>]
|
|
1890
|
+
market funding-rate <instId> [--history] [--limit <n>]
|
|
1891
|
+
market mark-price --instType <MARGIN|SWAP|FUTURES|OPTION> [--instId <id>]
|
|
1892
|
+
market trades <instId> [--limit <n>]
|
|
1893
|
+
market index-ticker [--instId <id>] [--quoteCcy <ccy>]
|
|
1894
|
+
market index-candles <instId> [--bar <bar>] [--limit <n>] [--history]
|
|
1895
|
+
market price-limit <instId>
|
|
1896
|
+
market open-interest --instType <SWAP|FUTURES|OPTION> [--instId <id>]
|
|
1016
1897
|
|
|
1017
1898
|
account balance [<ccy>]
|
|
1899
|
+
account asset-balance [--ccy <ccy>]
|
|
1900
|
+
account positions [--instType <type>] [--instId <id>]
|
|
1901
|
+
account positions-history [--instType <type>] [--instId <id>] [--limit <n>]
|
|
1902
|
+
account bills [--instType <type>] [--ccy <ccy>] [--limit <n>] [--archive]
|
|
1903
|
+
account fees --instType <type> [--instId <id>]
|
|
1904
|
+
account config
|
|
1905
|
+
account set-position-mode --posMode <long_short_mode|net_mode>
|
|
1906
|
+
account max-size --instId <id> --tdMode <cross|isolated> [--px <price>]
|
|
1907
|
+
account max-avail-size --instId <id> --tdMode <cross|isolated|cash>
|
|
1908
|
+
account max-withdrawal [--ccy <ccy>]
|
|
1909
|
+
account transfer --ccy <ccy> --amt <n> --from <acct> --to <acct> [--transferType <0|1|2|3>]
|
|
1018
1910
|
|
|
1019
1911
|
spot orders [--instId <id>] [--history]
|
|
1912
|
+
spot get --instId <id> --ordId <id>
|
|
1020
1913
|
spot fills [--instId <id>] [--ordId <id>]
|
|
1021
1914
|
spot place --instId <id> --side <buy|sell> --ordType <type> --sz <n> [--px <price>]
|
|
1915
|
+
spot amend --instId <id> --ordId <id> [--newSz <n>] [--newPx <price>]
|
|
1022
1916
|
spot cancel <instId> --ordId <id>
|
|
1023
1917
|
spot algo orders [--instId <id>] [--history] [--ordType <conditional|oco>]
|
|
1024
1918
|
spot algo place --instId <id> --side <buy|sell> --sz <n> [--ordType <conditional|oco>]
|
|
@@ -1030,10 +1924,14 @@ Commands:
|
|
|
1030
1924
|
spot algo cancel --instId <id> --algoId <id>
|
|
1031
1925
|
|
|
1032
1926
|
swap positions [<instId>]
|
|
1033
|
-
swap orders [--instId <id>] [--history]
|
|
1927
|
+
swap orders [--instId <id>] [--history] [--archive]
|
|
1928
|
+
swap get --instId <id> --ordId <id>
|
|
1929
|
+
swap fills [--instId <id>] [--ordId <id>] [--archive]
|
|
1034
1930
|
swap place --instId <id> --side <buy|sell> --ordType <type> --sz <n> [--posSide <side>] [--px <price>] [--tdMode <cross|isolated>]
|
|
1035
1931
|
swap cancel <instId> --ordId <id>
|
|
1932
|
+
swap close --instId <id> --mgnMode <cross|isolated> [--posSide <net|long|short>] [--autoCxl]
|
|
1036
1933
|
swap leverage --instId <id> --lever <n> --mgnMode <cross|isolated> [--posSide <side>]
|
|
1934
|
+
swap get-leverage --instId <id> --mgnMode <cross|isolated>
|
|
1037
1935
|
swap algo orders [--instId <id>] [--history] [--ordType <conditional|oco>]
|
|
1038
1936
|
swap algo trail --instId <id> --side <buy|sell> --sz <n> --callbackRatio <ratio>
|
|
1039
1937
|
[--activePx <price>] [--posSide <net|long|short>] [--tdMode <cross|isolated>] [--reduceOnly]
|
|
@@ -1046,8 +1944,26 @@ Commands:
|
|
|
1046
1944
|
[--newSlTriggerPx <price>] [--newSlOrdPx <price|-1>]
|
|
1047
1945
|
swap algo cancel --instId <id> --algoId <id>
|
|
1048
1946
|
|
|
1947
|
+
futures orders [--instId <id>] [--history] [--archive]
|
|
1948
|
+
futures positions [--instId <id>]
|
|
1949
|
+
futures fills [--instId <id>] [--ordId <id>] [--archive]
|
|
1950
|
+
futures place --instId <id> --side <buy|sell> --ordType <type> --sz <n> [--tdMode <cross|isolated>]
|
|
1951
|
+
[--posSide <net|long|short>] [--px <price>] [--reduceOnly]
|
|
1952
|
+
futures cancel <instId> --ordId <id>
|
|
1953
|
+
futures get --instId <id> --ordId <id>
|
|
1954
|
+
|
|
1955
|
+
bot grid orders --algoOrdType <grid|contract_grid|moon_grid> [--instId <id>] [--algoId <id>] [--history]
|
|
1956
|
+
bot grid details --algoOrdType <type> --algoId <id>
|
|
1957
|
+
bot grid sub-orders --algoOrdType <type> --algoId <id> [--live]
|
|
1958
|
+
bot grid create --instId <id> --algoOrdType <grid|contract_grid> --maxPx <px> --minPx <px> --gridNum <n>
|
|
1959
|
+
[--runType <1|2>] [--quoteSz <n>] [--baseSz <n>]
|
|
1960
|
+
[--direction <long|short|neutral>] [--lever <n>] [--sz <n>]
|
|
1961
|
+
bot grid stop --algoId <id> --algoOrdType <type> --instId <id> [--stopType <1|2|3|5|6>]
|
|
1962
|
+
|
|
1963
|
+
config init
|
|
1049
1964
|
config show
|
|
1050
1965
|
config set <key> <value>
|
|
1966
|
+
config setup-clients
|
|
1051
1967
|
`);
|
|
1052
1968
|
}
|
|
1053
1969
|
async function main() {
|
|
@@ -1056,6 +1972,7 @@ async function main() {
|
|
|
1056
1972
|
args: process.argv.slice(2),
|
|
1057
1973
|
options: {
|
|
1058
1974
|
profile: { type: "string" },
|
|
1975
|
+
demo: { type: "boolean", default: false },
|
|
1059
1976
|
json: { type: "boolean", default: false },
|
|
1060
1977
|
help: { type: "boolean", default: false },
|
|
1061
1978
|
// market candles
|
|
@@ -1091,7 +2008,34 @@ async function main() {
|
|
|
1091
2008
|
// trailing stop
|
|
1092
2009
|
callbackRatio: { type: "string" },
|
|
1093
2010
|
callbackSpread: { type: "string" },
|
|
1094
|
-
activePx: { type: "string" }
|
|
2011
|
+
activePx: { type: "string" },
|
|
2012
|
+
// grid bot
|
|
2013
|
+
algoOrdType: { type: "string" },
|
|
2014
|
+
gridNum: { type: "string" },
|
|
2015
|
+
maxPx: { type: "string" },
|
|
2016
|
+
minPx: { type: "string" },
|
|
2017
|
+
runType: { type: "string" },
|
|
2018
|
+
quoteSz: { type: "string" },
|
|
2019
|
+
baseSz: { type: "string" },
|
|
2020
|
+
direction: { type: "string" },
|
|
2021
|
+
stopType: { type: "string" },
|
|
2022
|
+
live: { type: "boolean", default: false },
|
|
2023
|
+
// market extras
|
|
2024
|
+
instType: { type: "string" },
|
|
2025
|
+
quoteCcy: { type: "string" },
|
|
2026
|
+
// account extras
|
|
2027
|
+
archive: { type: "boolean", default: false },
|
|
2028
|
+
posMode: { type: "string" },
|
|
2029
|
+
ccy: { type: "string" },
|
|
2030
|
+
from: { type: "string" },
|
|
2031
|
+
to: { type: "string" },
|
|
2032
|
+
transferType: { type: "string" },
|
|
2033
|
+
subAcct: { type: "string" },
|
|
2034
|
+
amt: { type: "string" },
|
|
2035
|
+
// swap/order extras
|
|
2036
|
+
autoCxl: { type: "boolean", default: false },
|
|
2037
|
+
clOrdId: { type: "string" },
|
|
2038
|
+
newPx: { type: "string" }
|
|
1095
2039
|
},
|
|
1096
2040
|
allowPositionals: true
|
|
1097
2041
|
});
|
|
@@ -1102,14 +2046,16 @@ async function main() {
|
|
|
1102
2046
|
const [module, action, ...rest] = positionals;
|
|
1103
2047
|
const json = values.json ?? false;
|
|
1104
2048
|
if (module === "config") {
|
|
2049
|
+
if (action === "init") return cmdConfigInit();
|
|
1105
2050
|
if (action === "show") return cmdConfigShow(json);
|
|
1106
2051
|
if (action === "set") return cmdConfigSet(rest[0], rest[1]);
|
|
2052
|
+
if (action === "setup-clients") return cmdSetupClients();
|
|
1107
2053
|
process.stderr.write(`Unknown config command: ${action}
|
|
1108
2054
|
`);
|
|
1109
2055
|
process.exitCode = 1;
|
|
1110
2056
|
return;
|
|
1111
2057
|
}
|
|
1112
|
-
const config = loadProfileConfig({ profile: values.profile });
|
|
2058
|
+
const config = loadProfileConfig({ profile: values.profile, demo: values.demo, userAgent: `okx-trade-cli/${CLI_VERSION}` });
|
|
1113
2059
|
const client = new OkxRestClient(config);
|
|
1114
2060
|
if (module === "market") {
|
|
1115
2061
|
if (action === "ticker") return cmdMarketTicker(client, rest[0], json);
|
|
@@ -1122,9 +2068,74 @@ async function main() {
|
|
|
1122
2068
|
limit: values.limit ? Number(values.limit) : void 0,
|
|
1123
2069
|
json
|
|
1124
2070
|
});
|
|
2071
|
+
if (action === "instruments")
|
|
2072
|
+
return cmdMarketInstruments(client, { instType: values.instType, instId: values.instId, json });
|
|
2073
|
+
if (action === "funding-rate")
|
|
2074
|
+
return cmdMarketFundingRate(client, rest[0], {
|
|
2075
|
+
history: values.history,
|
|
2076
|
+
limit: values.limit ? Number(values.limit) : void 0,
|
|
2077
|
+
json
|
|
2078
|
+
});
|
|
2079
|
+
if (action === "mark-price")
|
|
2080
|
+
return cmdMarketMarkPrice(client, { instType: values.instType, instId: values.instId, json });
|
|
2081
|
+
if (action === "trades")
|
|
2082
|
+
return cmdMarketTrades(client, rest[0], {
|
|
2083
|
+
limit: values.limit ? Number(values.limit) : void 0,
|
|
2084
|
+
json
|
|
2085
|
+
});
|
|
2086
|
+
if (action === "index-ticker")
|
|
2087
|
+
return cmdMarketIndexTicker(client, { instId: values.instId, quoteCcy: values.quoteCcy, json });
|
|
2088
|
+
if (action === "index-candles")
|
|
2089
|
+
return cmdMarketIndexCandles(client, rest[0], {
|
|
2090
|
+
bar: values.bar,
|
|
2091
|
+
limit: values.limit ? Number(values.limit) : void 0,
|
|
2092
|
+
history: values.history,
|
|
2093
|
+
json
|
|
2094
|
+
});
|
|
2095
|
+
if (action === "price-limit") return cmdMarketPriceLimit(client, rest[0], json);
|
|
2096
|
+
if (action === "open-interest")
|
|
2097
|
+
return cmdMarketOpenInterest(client, { instType: values.instType, instId: values.instId, json });
|
|
1125
2098
|
}
|
|
1126
2099
|
if (module === "account") {
|
|
1127
2100
|
if (action === "balance") return cmdAccountBalance(client, rest[0], json);
|
|
2101
|
+
if (action === "asset-balance") return cmdAccountAssetBalance(client, values.ccy, json);
|
|
2102
|
+
if (action === "positions")
|
|
2103
|
+
return cmdAccountPositions(client, { instType: values.instType, instId: values.instId, json });
|
|
2104
|
+
if (action === "positions-history")
|
|
2105
|
+
return cmdAccountPositionsHistory(client, {
|
|
2106
|
+
instType: values.instType,
|
|
2107
|
+
instId: values.instId,
|
|
2108
|
+
limit: values.limit ? Number(values.limit) : void 0,
|
|
2109
|
+
json
|
|
2110
|
+
});
|
|
2111
|
+
if (action === "bills")
|
|
2112
|
+
return cmdAccountBills(client, {
|
|
2113
|
+
archive: values.archive,
|
|
2114
|
+
instType: values.instType,
|
|
2115
|
+
ccy: values.ccy,
|
|
2116
|
+
limit: values.limit ? Number(values.limit) : void 0,
|
|
2117
|
+
json
|
|
2118
|
+
});
|
|
2119
|
+
if (action === "fees")
|
|
2120
|
+
return cmdAccountFees(client, { instType: values.instType, instId: values.instId, json });
|
|
2121
|
+
if (action === "config") return cmdAccountConfig(client, json);
|
|
2122
|
+
if (action === "set-position-mode")
|
|
2123
|
+
return cmdAccountSetPositionMode(client, values.posMode, json);
|
|
2124
|
+
if (action === "max-size")
|
|
2125
|
+
return cmdAccountMaxSize(client, { instId: values.instId, tdMode: values.tdMode, px: values.px, json });
|
|
2126
|
+
if (action === "max-avail-size")
|
|
2127
|
+
return cmdAccountMaxAvailSize(client, { instId: values.instId, tdMode: values.tdMode, json });
|
|
2128
|
+
if (action === "max-withdrawal") return cmdAccountMaxWithdrawal(client, values.ccy, json);
|
|
2129
|
+
if (action === "transfer")
|
|
2130
|
+
return cmdAccountTransfer(client, {
|
|
2131
|
+
ccy: values.ccy,
|
|
2132
|
+
amt: values.amt,
|
|
2133
|
+
from: values.from,
|
|
2134
|
+
to: values.to,
|
|
2135
|
+
transferType: values.transferType,
|
|
2136
|
+
subAcct: values.subAcct,
|
|
2137
|
+
json
|
|
2138
|
+
});
|
|
1128
2139
|
}
|
|
1129
2140
|
if (module === "spot") {
|
|
1130
2141
|
if (action === "orders")
|
|
@@ -1133,8 +2144,19 @@ async function main() {
|
|
|
1133
2144
|
status: values.history ? "history" : "open",
|
|
1134
2145
|
json
|
|
1135
2146
|
});
|
|
2147
|
+
if (action === "get")
|
|
2148
|
+
return cmdSpotGet(client, { instId: values.instId, ordId: values.ordId, clOrdId: values.clOrdId, json });
|
|
1136
2149
|
if (action === "fills")
|
|
1137
2150
|
return cmdSpotFills(client, { instId: values.instId, ordId: values.ordId, json });
|
|
2151
|
+
if (action === "amend")
|
|
2152
|
+
return cmdSpotAmend(client, {
|
|
2153
|
+
instId: values.instId,
|
|
2154
|
+
ordId: values.ordId,
|
|
2155
|
+
clOrdId: values.clOrdId,
|
|
2156
|
+
newSz: values.newSz,
|
|
2157
|
+
newPx: values.newPx,
|
|
2158
|
+
json
|
|
2159
|
+
});
|
|
1138
2160
|
if (action === "place")
|
|
1139
2161
|
return cmdSpotPlace(client, {
|
|
1140
2162
|
instId: values.instId,
|
|
@@ -1191,6 +2213,20 @@ async function main() {
|
|
|
1191
2213
|
status: values.history ? "history" : "open",
|
|
1192
2214
|
json
|
|
1193
2215
|
});
|
|
2216
|
+
if (action === "get")
|
|
2217
|
+
return cmdSwapGet(client, { instId: values.instId, ordId: values.ordId, clOrdId: values.clOrdId, json });
|
|
2218
|
+
if (action === "fills")
|
|
2219
|
+
return cmdSwapFills(client, { instId: values.instId, ordId: values.ordId, archive: values.archive, json });
|
|
2220
|
+
if (action === "close")
|
|
2221
|
+
return cmdSwapClose(client, {
|
|
2222
|
+
instId: values.instId,
|
|
2223
|
+
mgnMode: values.mgnMode,
|
|
2224
|
+
posSide: values.posSide,
|
|
2225
|
+
autoCxl: values.autoCxl,
|
|
2226
|
+
json
|
|
2227
|
+
});
|
|
2228
|
+
if (action === "get-leverage")
|
|
2229
|
+
return cmdSwapGetLeverage(client, { instId: values.instId, mgnMode: values.mgnMode, json });
|
|
1194
2230
|
if (action === "place")
|
|
1195
2231
|
return cmdSwapPlace(client, {
|
|
1196
2232
|
instId: values.instId,
|
|
@@ -1264,6 +2300,87 @@ async function main() {
|
|
|
1264
2300
|
});
|
|
1265
2301
|
}
|
|
1266
2302
|
}
|
|
2303
|
+
if (module === "futures") {
|
|
2304
|
+
if (action === "orders")
|
|
2305
|
+
return cmdFuturesOrders(client, {
|
|
2306
|
+
instId: values.instId,
|
|
2307
|
+
status: values.archive ? "archive" : values.history ? "history" : "open",
|
|
2308
|
+
json
|
|
2309
|
+
});
|
|
2310
|
+
if (action === "positions") return cmdFuturesPositions(client, values.instId, json);
|
|
2311
|
+
if (action === "fills")
|
|
2312
|
+
return cmdFuturesFills(client, {
|
|
2313
|
+
instId: values.instId,
|
|
2314
|
+
ordId: values.ordId,
|
|
2315
|
+
archive: values.archive,
|
|
2316
|
+
json
|
|
2317
|
+
});
|
|
2318
|
+
if (action === "place")
|
|
2319
|
+
return cmdFuturesPlace(client, {
|
|
2320
|
+
instId: values.instId,
|
|
2321
|
+
side: values.side,
|
|
2322
|
+
ordType: values.ordType,
|
|
2323
|
+
sz: values.sz,
|
|
2324
|
+
tdMode: values.tdMode ?? "cross",
|
|
2325
|
+
posSide: values.posSide,
|
|
2326
|
+
px: values.px,
|
|
2327
|
+
reduceOnly: values.reduceOnly,
|
|
2328
|
+
json
|
|
2329
|
+
});
|
|
2330
|
+
if (action === "cancel")
|
|
2331
|
+
return cmdFuturesCancel(client, rest[0] ?? values.instId, values.ordId, json);
|
|
2332
|
+
if (action === "get")
|
|
2333
|
+
return cmdFuturesGet(client, { instId: rest[0] ?? values.instId, ordId: values.ordId, json });
|
|
2334
|
+
}
|
|
2335
|
+
if (module === "bot") {
|
|
2336
|
+
const subAction = rest[0];
|
|
2337
|
+
if (action === "grid") {
|
|
2338
|
+
if (subAction === "orders")
|
|
2339
|
+
return cmdGridOrders(client, {
|
|
2340
|
+
algoOrdType: values.algoOrdType,
|
|
2341
|
+
instId: values.instId,
|
|
2342
|
+
algoId: values.algoId,
|
|
2343
|
+
status: values.history ? "history" : "active",
|
|
2344
|
+
json
|
|
2345
|
+
});
|
|
2346
|
+
if (subAction === "details")
|
|
2347
|
+
return cmdGridDetails(client, {
|
|
2348
|
+
algoOrdType: values.algoOrdType,
|
|
2349
|
+
algoId: values.algoId,
|
|
2350
|
+
json
|
|
2351
|
+
});
|
|
2352
|
+
if (subAction === "sub-orders")
|
|
2353
|
+
return cmdGridSubOrders(client, {
|
|
2354
|
+
algoOrdType: values.algoOrdType,
|
|
2355
|
+
algoId: values.algoId,
|
|
2356
|
+
type: values.live ? "live" : "filled",
|
|
2357
|
+
json
|
|
2358
|
+
});
|
|
2359
|
+
if (subAction === "create")
|
|
2360
|
+
return cmdGridCreate(client, {
|
|
2361
|
+
instId: values.instId,
|
|
2362
|
+
algoOrdType: values.algoOrdType,
|
|
2363
|
+
maxPx: values.maxPx,
|
|
2364
|
+
minPx: values.minPx,
|
|
2365
|
+
gridNum: values.gridNum,
|
|
2366
|
+
runType: values.runType,
|
|
2367
|
+
quoteSz: values.quoteSz,
|
|
2368
|
+
baseSz: values.baseSz,
|
|
2369
|
+
direction: values.direction,
|
|
2370
|
+
lever: values.lever,
|
|
2371
|
+
sz: values.sz,
|
|
2372
|
+
json
|
|
2373
|
+
});
|
|
2374
|
+
if (subAction === "stop")
|
|
2375
|
+
return cmdGridStop(client, {
|
|
2376
|
+
algoId: values.algoId,
|
|
2377
|
+
algoOrdType: values.algoOrdType,
|
|
2378
|
+
instId: values.instId,
|
|
2379
|
+
stopType: values.stopType,
|
|
2380
|
+
json
|
|
2381
|
+
});
|
|
2382
|
+
}
|
|
2383
|
+
}
|
|
1267
2384
|
process.stderr.write(`Unknown command: ${module} ${action ?? ""}
|
|
1268
2385
|
`);
|
|
1269
2386
|
process.exitCode = 1;
|
|
@@ -1271,8 +2388,12 @@ async function main() {
|
|
|
1271
2388
|
main().catch((error) => {
|
|
1272
2389
|
const payload = toToolErrorPayload(error);
|
|
1273
2390
|
process.stderr.write(`Error: ${payload.message}
|
|
2391
|
+
`);
|
|
2392
|
+
if (payload.traceId) process.stderr.write(`TraceId: ${payload.traceId}
|
|
1274
2393
|
`);
|
|
1275
2394
|
if (payload.suggestion) process.stderr.write(`Hint: ${payload.suggestion}
|
|
2395
|
+
`);
|
|
2396
|
+
process.stderr.write(`Version: okx-trade-cli@${CLI_VERSION}
|
|
1276
2397
|
`);
|
|
1277
2398
|
process.exitCode = 1;
|
|
1278
2399
|
});
|