okx-trade-cli 1.0.4 → 1.0.7

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.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/index.ts","../../core/src/utils/signature.ts","../../core/src/utils/errors.ts","../../core/src/utils/rate-limiter.ts","../../core/src/client/rest-client.ts","../../core/src/tools/helpers.ts","../../core/src/tools/common.ts","../../core/src/tools/account.ts","../../core/src/tools/algo-trade.ts","../../core/src/tools/audit.ts","../../core/src/tools/bot/grid.ts","../../core/src/tools/bot/index.ts","../../core/src/tools/futures-trade.ts","../../core/src/tools/market.ts","../../core/src/tools/spot-trade.ts","../../core/src/tools/swap-trade.ts","../../core/src/tools/index.ts","../../core/src/tools/types.ts","../../core/src/constants.ts","../../core/src/config/toml.ts","../../core/src/config.ts","../../core/src/utils/update-check.ts","../../core/src/utils/logger.ts","../src/config/loader.ts","../src/formatter.ts","../src/commands/market.ts","../src/commands/account.ts","../src/commands/spot.ts","../src/commands/swap.ts","../src/commands/futures.ts","../src/config/toml.ts","../src/commands/config.ts","../src/commands/client-setup.ts","../src/commands/bot.ts"],"sourcesContent":["import { parseArgs } from \"node:util\";\nimport { createRequire } from \"node:module\";\nimport { OkxRestClient, toToolErrorPayload, checkForUpdates } from \"@okx-hub/core\";\n\nconst _require = createRequire(import.meta.url);\nconst CLI_VERSION = (_require(\"../package.json\") as { version: string }).version;\nimport { loadProfileConfig } from \"./config/loader.js\";\nimport {\n cmdMarketTicker,\n cmdMarketTickers,\n cmdMarketOrderbook,\n cmdMarketCandles,\n cmdMarketInstruments,\n cmdMarketFundingRate,\n cmdMarketMarkPrice,\n cmdMarketTrades,\n cmdMarketIndexTicker,\n cmdMarketIndexCandles,\n cmdMarketPriceLimit,\n cmdMarketOpenInterest,\n} from \"./commands/market.js\";\nimport {\n cmdAccountBalance,\n cmdAccountAssetBalance,\n cmdAccountPositions,\n cmdAccountBills,\n cmdAccountFees,\n cmdAccountConfig,\n cmdAccountSetPositionMode,\n cmdAccountMaxSize,\n cmdAccountMaxAvailSize,\n cmdAccountMaxWithdrawal,\n cmdAccountPositionsHistory,\n cmdAccountTransfer,\n} from \"./commands/account.js\";\nimport {\n cmdSpotOrders,\n cmdSpotPlace,\n cmdSpotCancel,\n cmdSpotFills,\n cmdSpotGet,\n cmdSpotAmend,\n cmdSpotAlgoPlace,\n cmdSpotAlgoAmend,\n cmdSpotAlgoCancel,\n cmdSpotAlgoOrders,\n} from \"./commands/spot.js\";\nimport {\n cmdSwapPositions,\n cmdSwapOrders,\n cmdSwapPlace,\n cmdSwapCancel,\n cmdSwapFills,\n cmdSwapGet,\n cmdSwapClose,\n cmdSwapGetLeverage,\n cmdSwapSetLeverage,\n cmdSwapAlgoPlace,\n cmdSwapAlgoAmend,\n cmdSwapAlgoCancel,\n cmdSwapAlgoOrders,\n cmdSwapAlgoTrailPlace,\n} from \"./commands/swap.js\";\nimport {\n cmdFuturesOrders,\n cmdFuturesPositions,\n cmdFuturesFills,\n cmdFuturesPlace,\n cmdFuturesCancel,\n cmdFuturesGet,\n} from \"./commands/futures.js\";\nimport { cmdConfigShow, cmdConfigSet, cmdConfigInit } from \"./commands/config.js\";\nimport { cmdSetupClients } from \"./commands/client-setup.js\";\nimport {\n cmdGridOrders,\n cmdGridDetails,\n cmdGridSubOrders,\n cmdGridCreate,\n cmdGridStop,\n} from \"./commands/bot.js\";\n\nfunction printHelp(): void {\n process.stdout.write(`\nUsage: okx [--profile <name>] [--json] <command> [args]\n\nGlobal Options:\n --profile <name> Use a named profile from ~/.okx/config.toml\n --demo Use simulated trading (demo) mode\n --json Output raw JSON\n --help Show this help\n\nCommands:\n market ticker <instId>\n market tickers <instType> (SPOT|SWAP|FUTURES|OPTION)\n market orderbook <instId> [--sz <n>]\n market candles <instId> [--bar <bar>] [--limit <n>]\n market instruments --instType <type> [--instId <id>]\n market funding-rate <instId> [--history] [--limit <n>]\n market mark-price --instType <MARGIN|SWAP|FUTURES|OPTION> [--instId <id>]\n market trades <instId> [--limit <n>]\n market index-ticker [--instId <id>] [--quoteCcy <ccy>]\n market index-candles <instId> [--bar <bar>] [--limit <n>] [--history]\n market price-limit <instId>\n market open-interest --instType <SWAP|FUTURES|OPTION> [--instId <id>]\n\n account balance [<ccy>]\n account asset-balance [--ccy <ccy>]\n account positions [--instType <type>] [--instId <id>]\n account positions-history [--instType <type>] [--instId <id>] [--limit <n>]\n account bills [--instType <type>] [--ccy <ccy>] [--limit <n>] [--archive]\n account fees --instType <type> [--instId <id>]\n account config\n account set-position-mode --posMode <long_short_mode|net_mode>\n account max-size --instId <id> --tdMode <cross|isolated> [--px <price>]\n account max-avail-size --instId <id> --tdMode <cross|isolated|cash>\n account max-withdrawal [--ccy <ccy>]\n account transfer --ccy <ccy> --amt <n> --from <acct> --to <acct> [--transferType <0|1|2|3>]\n\n spot orders [--instId <id>] [--history]\n spot get --instId <id> --ordId <id>\n spot fills [--instId <id>] [--ordId <id>]\n spot place --instId <id> --side <buy|sell> --ordType <type> --sz <n> [--px <price>]\n spot amend --instId <id> --ordId <id> [--newSz <n>] [--newPx <price>]\n spot cancel <instId> --ordId <id>\n spot algo orders [--instId <id>] [--history] [--ordType <conditional|oco>]\n spot algo place --instId <id> --side <buy|sell> --sz <n> [--ordType <conditional|oco>]\n [--tpTriggerPx <price>] [--tpOrdPx <price|-1>]\n [--slTriggerPx <price>] [--slOrdPx <price|-1>]\n spot algo amend --instId <id> --algoId <id> [--newSz <n>]\n [--newTpTriggerPx <price>] [--newTpOrdPx <price|-1>]\n [--newSlTriggerPx <price>] [--newSlOrdPx <price|-1>]\n spot algo cancel --instId <id> --algoId <id>\n\n swap positions [<instId>]\n swap orders [--instId <id>] [--history] [--archive]\n swap get --instId <id> --ordId <id>\n swap fills [--instId <id>] [--ordId <id>] [--archive]\n swap place --instId <id> --side <buy|sell> --ordType <type> --sz <n> [--posSide <side>] [--px <price>] [--tdMode <cross|isolated>]\n swap cancel <instId> --ordId <id>\n swap close --instId <id> --mgnMode <cross|isolated> [--posSide <net|long|short>] [--autoCxl]\n swap leverage --instId <id> --lever <n> --mgnMode <cross|isolated> [--posSide <side>]\n swap get-leverage --instId <id> --mgnMode <cross|isolated>\n swap algo orders [--instId <id>] [--history] [--ordType <conditional|oco>]\n swap algo trail --instId <id> --side <buy|sell> --sz <n> --callbackRatio <ratio>\n [--activePx <price>] [--posSide <net|long|short>] [--tdMode <cross|isolated>] [--reduceOnly]\n swap algo place --instId <id> --side <buy|sell> --sz <n> [--ordType <conditional|oco>]\n [--tpTriggerPx <price>] [--tpOrdPx <price|-1>]\n [--slTriggerPx <price>] [--slOrdPx <price|-1>]\n [--posSide <net|long|short>] [--tdMode <cross|isolated>] [--reduceOnly]\n swap algo amend --instId <id> --algoId <id> [--newSz <n>]\n [--newTpTriggerPx <price>] [--newTpOrdPx <price|-1>]\n [--newSlTriggerPx <price>] [--newSlOrdPx <price|-1>]\n swap algo cancel --instId <id> --algoId <id>\n\n futures orders [--instId <id>] [--history] [--archive]\n futures positions [--instId <id>]\n futures fills [--instId <id>] [--ordId <id>] [--archive]\n futures place --instId <id> --side <buy|sell> --ordType <type> --sz <n> [--tdMode <cross|isolated>]\n [--posSide <net|long|short>] [--px <price>] [--reduceOnly]\n futures cancel <instId> --ordId <id>\n futures get --instId <id> --ordId <id>\n\n bot grid orders --algoOrdType <grid|contract_grid|moon_grid> [--instId <id>] [--algoId <id>] [--history]\n bot grid details --algoOrdType <type> --algoId <id>\n bot grid sub-orders --algoOrdType <type> --algoId <id> [--live]\n bot grid create --instId <id> --algoOrdType <grid|contract_grid> --maxPx <px> --minPx <px> --gridNum <n>\n [--runType <1|2>] [--quoteSz <n>] [--baseSz <n>]\n [--direction <long|short|neutral>] [--lever <n>] [--sz <n>]\n bot grid stop --algoId <id> --algoOrdType <type> --instId <id> [--stopType <1|2|3|5|6>]\n\n config init\n config show\n config set <key> <value>\n config setup-clients\n`);\n}\n\nasync function main(): Promise<void> {\n checkForUpdates(\"okx-trade-cli\", CLI_VERSION);\n\n const { values, positionals } = parseArgs({\n args: process.argv.slice(2),\n options: {\n profile: { type: \"string\" },\n demo: { type: \"boolean\", default: false },\n json: { type: \"boolean\", default: false },\n help: { type: \"boolean\", default: false },\n // market candles\n bar: { type: \"string\" },\n limit: { type: \"string\" },\n sz: { type: \"string\" },\n // orders\n instId: { type: \"string\" },\n history: { type: \"boolean\", default: false },\n ordId: { type: \"string\" },\n // trade\n side: { type: \"string\" },\n ordType: { type: \"string\" },\n px: { type: \"string\" },\n posSide: { type: \"string\" },\n tdMode: { type: \"string\" },\n // leverage\n lever: { type: \"string\" },\n mgnMode: { type: \"string\" },\n // algo orders\n tpTriggerPx: { type: \"string\" },\n tpOrdPx: { type: \"string\" },\n slTriggerPx: { type: \"string\" },\n slOrdPx: { type: \"string\" },\n algoId: { type: \"string\" },\n reduceOnly: { type: \"boolean\", default: false },\n // algo amend\n newSz: { type: \"string\" },\n newTpTriggerPx: { type: \"string\" },\n newTpOrdPx: { type: \"string\" },\n newSlTriggerPx: { type: \"string\" },\n newSlOrdPx: { type: \"string\" },\n // trailing stop\n callbackRatio: { type: \"string\" },\n callbackSpread: { type: \"string\" },\n activePx: { type: \"string\" },\n // grid bot\n algoOrdType: { type: \"string\" },\n gridNum: { type: \"string\" },\n maxPx: { type: \"string\" },\n minPx: { type: \"string\" },\n runType: { type: \"string\" },\n quoteSz: { type: \"string\" },\n baseSz: { type: \"string\" },\n direction: { type: \"string\" },\n stopType: { type: \"string\" },\n live: { type: \"boolean\", default: false },\n // market extras\n instType: { type: \"string\" },\n quoteCcy: { type: \"string\" },\n // account extras\n archive: { type: \"boolean\", default: false },\n posMode: { type: \"string\" },\n ccy: { type: \"string\" },\n from: { type: \"string\" },\n to: { type: \"string\" },\n transferType: { type: \"string\" },\n subAcct: { type: \"string\" },\n amt: { type: \"string\" },\n // swap/order extras\n autoCxl: { type: \"boolean\", default: false },\n clOrdId: { type: \"string\" },\n newPx: { type: \"string\" },\n },\n allowPositionals: true,\n });\n\n if (values.help || positionals.length === 0) {\n printHelp();\n return;\n }\n\n const [module, action, ...rest] = positionals;\n const json = values.json ?? false;\n\n // config commands don't need a client\n if (module === \"config\") {\n if (action === \"init\") return cmdConfigInit();\n if (action === \"show\") return cmdConfigShow(json);\n if (action === \"set\") return cmdConfigSet(rest[0], rest[1]);\n if (action === \"setup-clients\") return cmdSetupClients();\n process.stderr.write(`Unknown config command: ${action}\\n`);\n process.exitCode = 1;\n return;\n }\n\n const config = loadProfileConfig({ profile: values.profile, demo: values.demo, userAgent: `okx-trade-cli/${CLI_VERSION}` });\n const client = new OkxRestClient(config);\n\n if (module === \"market\") {\n if (action === \"ticker\") return cmdMarketTicker(client, rest[0], json);\n if (action === \"tickers\") return cmdMarketTickers(client, rest[0], json);\n if (action === \"orderbook\")\n return cmdMarketOrderbook(client, rest[0], values.sz ? Number(values.sz) : undefined, json);\n if (action === \"candles\")\n return cmdMarketCandles(client, rest[0], {\n bar: values.bar,\n limit: values.limit ? Number(values.limit) : undefined,\n json,\n });\n if (action === \"instruments\")\n return cmdMarketInstruments(client, { instType: values.instType!, instId: values.instId, json });\n if (action === \"funding-rate\")\n return cmdMarketFundingRate(client, rest[0], {\n history: values.history,\n limit: values.limit ? Number(values.limit) : undefined,\n json,\n });\n if (action === \"mark-price\")\n return cmdMarketMarkPrice(client, { instType: values.instType!, instId: values.instId, json });\n if (action === \"trades\")\n return cmdMarketTrades(client, rest[0], {\n limit: values.limit ? Number(values.limit) : undefined,\n json,\n });\n if (action === \"index-ticker\")\n return cmdMarketIndexTicker(client, { instId: values.instId, quoteCcy: values.quoteCcy, json });\n if (action === \"index-candles\")\n return cmdMarketIndexCandles(client, rest[0], {\n bar: values.bar,\n limit: values.limit ? Number(values.limit) : undefined,\n history: values.history,\n json,\n });\n if (action === \"price-limit\") return cmdMarketPriceLimit(client, rest[0], json);\n if (action === \"open-interest\")\n return cmdMarketOpenInterest(client, { instType: values.instType!, instId: values.instId, json });\n }\n\n if (module === \"account\") {\n if (action === \"balance\") return cmdAccountBalance(client, rest[0], json);\n if (action === \"asset-balance\") return cmdAccountAssetBalance(client, values.ccy, json);\n if (action === \"positions\")\n return cmdAccountPositions(client, { instType: values.instType, instId: values.instId, json });\n if (action === \"positions-history\")\n return cmdAccountPositionsHistory(client, {\n instType: values.instType,\n instId: values.instId,\n limit: values.limit ? Number(values.limit) : undefined,\n json,\n });\n if (action === \"bills\")\n return cmdAccountBills(client, {\n archive: values.archive,\n instType: values.instType,\n ccy: values.ccy,\n limit: values.limit ? Number(values.limit) : undefined,\n json,\n });\n if (action === \"fees\")\n return cmdAccountFees(client, { instType: values.instType!, instId: values.instId, json });\n if (action === \"config\") return cmdAccountConfig(client, json);\n if (action === \"set-position-mode\")\n return cmdAccountSetPositionMode(client, values.posMode!, json);\n if (action === \"max-size\")\n return cmdAccountMaxSize(client, { instId: values.instId!, tdMode: values.tdMode!, px: values.px, json });\n if (action === \"max-avail-size\")\n return cmdAccountMaxAvailSize(client, { instId: values.instId!, tdMode: values.tdMode!, json });\n if (action === \"max-withdrawal\") return cmdAccountMaxWithdrawal(client, values.ccy, json);\n if (action === \"transfer\")\n return cmdAccountTransfer(client, {\n ccy: values.ccy!,\n amt: values.amt!,\n from: values.from!,\n to: values.to!,\n transferType: values.transferType,\n subAcct: values.subAcct,\n json,\n });\n }\n\n if (module === \"spot\") {\n if (action === \"orders\")\n return cmdSpotOrders(client, {\n instId: values.instId,\n status: values.history ? \"history\" : \"open\",\n json,\n });\n if (action === \"get\")\n return cmdSpotGet(client, { instId: values.instId!, ordId: values.ordId, clOrdId: values.clOrdId, json });\n if (action === \"fills\")\n return cmdSpotFills(client, { instId: values.instId, ordId: values.ordId, json });\n if (action === \"amend\")\n return cmdSpotAmend(client, {\n instId: values.instId!,\n ordId: values.ordId,\n clOrdId: values.clOrdId,\n newSz: values.newSz,\n newPx: values.newPx,\n json,\n });\n if (action === \"place\")\n return cmdSpotPlace(client, {\n instId: values.instId!,\n side: values.side!,\n ordType: values.ordType!,\n sz: values.sz!,\n px: values.px,\n json,\n });\n if (action === \"cancel\")\n return cmdSpotCancel(client, rest[0], values.ordId!, json);\n if (action === \"algo\") {\n const subAction = rest[0];\n if (subAction === \"place\")\n return cmdSpotAlgoPlace(client, {\n instId: values.instId!,\n side: values.side!,\n ordType: values.ordType ?? \"conditional\",\n sz: values.sz!,\n tpTriggerPx: values.tpTriggerPx,\n tpOrdPx: values.tpOrdPx,\n slTriggerPx: values.slTriggerPx,\n slOrdPx: values.slOrdPx,\n json,\n });\n if (subAction === \"amend\")\n return cmdSpotAlgoAmend(client, {\n instId: values.instId!,\n algoId: values.algoId!,\n newSz: values.newSz,\n newTpTriggerPx: values.newTpTriggerPx,\n newTpOrdPx: values.newTpOrdPx,\n newSlTriggerPx: values.newSlTriggerPx,\n newSlOrdPx: values.newSlOrdPx,\n json,\n });\n if (subAction === \"cancel\")\n return cmdSpotAlgoCancel(client, values.instId!, values.algoId!, json);\n if (subAction === \"orders\")\n return cmdSpotAlgoOrders(client, {\n instId: values.instId,\n status: values.history ? \"history\" : \"pending\",\n ordType: values.ordType,\n json,\n });\n }\n }\n\n if (module === \"swap\") {\n if (action === \"positions\")\n return cmdSwapPositions(client, rest[0] ?? values.instId, json);\n if (action === \"orders\")\n return cmdSwapOrders(client, {\n instId: values.instId,\n status: values.history ? \"history\" : \"open\",\n json,\n });\n if (action === \"get\")\n return cmdSwapGet(client, { instId: values.instId!, ordId: values.ordId, clOrdId: values.clOrdId, json });\n if (action === \"fills\")\n return cmdSwapFills(client, { instId: values.instId, ordId: values.ordId, archive: values.archive, json });\n if (action === \"close\")\n return cmdSwapClose(client, {\n instId: values.instId!,\n mgnMode: values.mgnMode!,\n posSide: values.posSide,\n autoCxl: values.autoCxl,\n json,\n });\n if (action === \"get-leverage\")\n return cmdSwapGetLeverage(client, { instId: values.instId!, mgnMode: values.mgnMode!, json });\n if (action === \"place\")\n return cmdSwapPlace(client, {\n instId: values.instId!,\n side: values.side!,\n ordType: values.ordType!,\n sz: values.sz!,\n posSide: values.posSide,\n px: values.px,\n tdMode: values.tdMode ?? \"cross\",\n json,\n });\n if (action === \"cancel\")\n return cmdSwapCancel(client, rest[0], values.ordId!, json);\n if (action === \"leverage\")\n return cmdSwapSetLeverage(client, {\n instId: values.instId!,\n lever: values.lever!,\n mgnMode: values.mgnMode!,\n posSide: values.posSide,\n json,\n });\n if (action === \"algo\") {\n const subAction = rest[0];\n if (subAction === \"trail\")\n return cmdSwapAlgoTrailPlace(client, {\n instId: values.instId!,\n side: values.side!,\n sz: values.sz!,\n callbackRatio: values.callbackRatio,\n callbackSpread: values.callbackSpread,\n activePx: values.activePx,\n posSide: values.posSide,\n tdMode: values.tdMode ?? \"cross\",\n reduceOnly: values.reduceOnly,\n json,\n });\n if (subAction === \"place\")\n return cmdSwapAlgoPlace(client, {\n instId: values.instId!,\n side: values.side!,\n ordType: values.ordType ?? \"conditional\",\n sz: values.sz!,\n posSide: values.posSide,\n tdMode: values.tdMode ?? \"cross\",\n tpTriggerPx: values.tpTriggerPx,\n tpOrdPx: values.tpOrdPx,\n slTriggerPx: values.slTriggerPx,\n slOrdPx: values.slOrdPx,\n reduceOnly: values.reduceOnly,\n json,\n });\n if (subAction === \"amend\")\n return cmdSwapAlgoAmend(client, {\n instId: values.instId!,\n algoId: values.algoId!,\n newSz: values.newSz,\n newTpTriggerPx: values.newTpTriggerPx,\n newTpOrdPx: values.newTpOrdPx,\n newSlTriggerPx: values.newSlTriggerPx,\n newSlOrdPx: values.newSlOrdPx,\n json,\n });\n if (subAction === \"cancel\")\n return cmdSwapAlgoCancel(client, values.instId!, values.algoId!, json);\n if (subAction === \"orders\")\n return cmdSwapAlgoOrders(client, {\n instId: values.instId,\n status: values.history ? \"history\" : \"pending\",\n ordType: values.ordType,\n json,\n });\n }\n }\n\n if (module === \"futures\") {\n if (action === \"orders\")\n return cmdFuturesOrders(client, {\n instId: values.instId,\n status: values.archive ? \"archive\" : values.history ? \"history\" : \"open\",\n json,\n });\n if (action === \"positions\") return cmdFuturesPositions(client, values.instId, json);\n if (action === \"fills\")\n return cmdFuturesFills(client, {\n instId: values.instId,\n ordId: values.ordId,\n archive: values.archive,\n json,\n });\n if (action === \"place\")\n return cmdFuturesPlace(client, {\n instId: values.instId!,\n side: values.side!,\n ordType: values.ordType!,\n sz: values.sz!,\n tdMode: values.tdMode ?? \"cross\",\n posSide: values.posSide,\n px: values.px,\n reduceOnly: values.reduceOnly,\n json,\n });\n if (action === \"cancel\")\n return cmdFuturesCancel(client, rest[0] ?? values.instId!, values.ordId!, json);\n if (action === \"get\")\n return cmdFuturesGet(client, { instId: rest[0] ?? values.instId!, ordId: values.ordId, json });\n }\n\n if (module === \"bot\") {\n const subAction = rest[0]; // e.g. \"orders\", \"details\", \"sub-orders\", \"create\", \"stop\"\n if (action === \"grid\") {\n if (subAction === \"orders\")\n return cmdGridOrders(client, {\n algoOrdType: values.algoOrdType!,\n instId: values.instId,\n algoId: values.algoId,\n status: values.history ? \"history\" : \"active\",\n json,\n });\n if (subAction === \"details\")\n return cmdGridDetails(client, {\n algoOrdType: values.algoOrdType!,\n algoId: values.algoId!,\n json,\n });\n if (subAction === \"sub-orders\")\n return cmdGridSubOrders(client, {\n algoOrdType: values.algoOrdType!,\n algoId: values.algoId!,\n type: values.live ? \"live\" : \"filled\",\n json,\n });\n if (subAction === \"create\")\n return cmdGridCreate(client, {\n instId: values.instId!,\n algoOrdType: values.algoOrdType!,\n maxPx: values.maxPx!,\n minPx: values.minPx!,\n gridNum: values.gridNum!,\n runType: values.runType,\n quoteSz: values.quoteSz,\n baseSz: values.baseSz,\n direction: values.direction,\n lever: values.lever,\n sz: values.sz,\n json,\n });\n if (subAction === \"stop\")\n return cmdGridStop(client, {\n algoId: values.algoId!,\n algoOrdType: values.algoOrdType!,\n instId: values.instId!,\n stopType: values.stopType,\n json,\n });\n }\n }\n\n process.stderr.write(`Unknown command: ${module} ${action ?? \"\"}\\n`);\n process.exitCode = 1;\n}\n\nmain().catch((error: unknown) => {\n const payload = toToolErrorPayload(error);\n process.stderr.write(`Error: ${payload.message}\\n`);\n if (payload.traceId) process.stderr.write(`TraceId: ${payload.traceId}\\n`);\n if (payload.suggestion) process.stderr.write(`Hint: ${payload.suggestion}\\n`);\n process.stderr.write(`Version: okx-trade-cli@${CLI_VERSION}\\n`);\n process.exitCode = 1;\n});\n","import { createHmac } from \"node:crypto\";\n\nexport function getNow(): string {\n return new Date().toISOString();\n}\n\nexport function signOkxPayload(payload: string, secretKey: string): string {\n return createHmac(\"sha256\", secretKey).update(payload).digest(\"base64\");\n}\n","export type ErrorType =\n | \"ConfigError\"\n | \"AuthenticationError\"\n | \"RateLimitError\"\n | \"ValidationError\"\n | \"OkxApiError\"\n | \"NetworkError\"\n | \"InternalError\";\n\nexport interface ToolErrorPayload {\n error: true;\n type: ErrorType;\n code?: string;\n message: string;\n suggestion?: string;\n endpoint?: string;\n traceId?: string;\n timestamp: string;\n}\n\nexport class OkxMcpError extends Error {\n public readonly type: ErrorType;\n public readonly code?: string;\n public readonly suggestion?: string;\n public readonly endpoint?: string;\n public readonly traceId?: string;\n\n public constructor(\n type: ErrorType,\n message: string,\n options?: {\n code?: string;\n suggestion?: string;\n endpoint?: string;\n traceId?: string;\n cause?: unknown;\n },\n ) {\n super(message, options?.cause ? { cause: options.cause } : undefined);\n this.name = type;\n this.type = type;\n this.code = options?.code;\n this.suggestion = options?.suggestion;\n this.endpoint = options?.endpoint;\n this.traceId = options?.traceId;\n }\n}\n\nexport class ConfigError extends OkxMcpError {\n public constructor(message: string, suggestion?: string) {\n super(\"ConfigError\", message, { suggestion });\n }\n}\n\nexport class ValidationError extends OkxMcpError {\n public constructor(message: string, suggestion?: string) {\n super(\"ValidationError\", message, { suggestion });\n }\n}\n\nexport class RateLimitError extends OkxMcpError {\n public constructor(\n message: string,\n suggestion?: string,\n endpoint?: string,\n traceId?: string,\n ) {\n super(\"RateLimitError\", message, { suggestion, endpoint, traceId });\n }\n}\n\nexport class AuthenticationError extends OkxMcpError {\n public constructor(\n message: string,\n suggestion?: string,\n endpoint?: string,\n traceId?: string,\n ) {\n super(\"AuthenticationError\", message, { suggestion, endpoint, traceId });\n }\n}\n\nexport class OkxApiError extends OkxMcpError {\n public constructor(\n message: string,\n options?: {\n code?: string;\n suggestion?: string;\n endpoint?: string;\n traceId?: string;\n cause?: unknown;\n },\n ) {\n super(\"OkxApiError\", message, options);\n }\n}\n\nexport class NetworkError extends OkxMcpError {\n public constructor(message: string, endpoint?: string, cause?: unknown) {\n super(\"NetworkError\", message, {\n endpoint,\n cause,\n suggestion:\n \"Please check network connectivity and retry the request in a few seconds.\",\n });\n }\n}\n\nexport function toToolErrorPayload(\n error: unknown,\n fallbackEndpoint?: string,\n): ToolErrorPayload {\n if (error instanceof OkxMcpError) {\n return {\n error: true,\n type: error.type,\n code: error.code,\n message: error.message,\n suggestion: error.suggestion,\n endpoint: error.endpoint ?? fallbackEndpoint,\n traceId: error.traceId,\n timestamp: new Date().toISOString(),\n };\n }\n\n const message = error instanceof Error ? error.message : String(error);\n\n return {\n error: true,\n type: \"InternalError\",\n message,\n suggestion:\n \"Unexpected server error. Check tool arguments and retry. If it persists, inspect server logs.\",\n endpoint: fallbackEndpoint,\n timestamp: new Date().toISOString(),\n };\n}\n","import { RateLimitError } from \"./errors.js\";\n\ntype Bucket = {\n tokens: number;\n lastRefillMs: number;\n capacity: number;\n refillPerSecond: number;\n};\n\nexport type RateLimitConfig = {\n key: string;\n capacity: number;\n refillPerSecond: number;\n};\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n}\n\nexport class RateLimiter {\n private readonly buckets = new Map<string, Bucket>();\n private readonly maxWaitMs: number;\n\n public constructor(maxWaitMs = 30_000) {\n this.maxWaitMs = maxWaitMs;\n }\n\n public async consume(config: RateLimitConfig, amount = 1): Promise<void> {\n const bucket = this.getBucket(config);\n this.refill(bucket);\n\n if (bucket.tokens >= amount) {\n bucket.tokens -= amount;\n return;\n }\n\n const missing = amount - bucket.tokens;\n const secondsToWait = missing / bucket.refillPerSecond;\n const waitMs = Math.ceil(secondsToWait * 1000);\n\n if (waitMs > this.maxWaitMs) {\n throw new RateLimitError(\n `Client-side rate limit reached for ${config.key}. Required wait ${waitMs}ms exceeds allowed max ${this.maxWaitMs}ms.`,\n \"Reduce tool call frequency or retry later.\",\n );\n }\n\n await sleep(waitMs);\n this.refill(bucket);\n\n if (bucket.tokens < amount) {\n throw new RateLimitError(\n `Rate limiter failed to acquire enough tokens for ${config.key}.`,\n );\n }\n\n bucket.tokens -= amount;\n }\n\n private getBucket(config: RateLimitConfig): Bucket {\n const existing = this.buckets.get(config.key);\n if (existing) {\n if (\n existing.capacity !== config.capacity ||\n existing.refillPerSecond !== config.refillPerSecond\n ) {\n existing.capacity = config.capacity;\n existing.refillPerSecond = config.refillPerSecond;\n existing.tokens = Math.min(existing.tokens, config.capacity);\n }\n return existing;\n }\n\n const now = Date.now();\n const created: Bucket = {\n tokens: config.capacity,\n lastRefillMs: now,\n capacity: config.capacity,\n refillPerSecond: config.refillPerSecond,\n };\n this.buckets.set(config.key, created);\n return created;\n }\n\n private refill(bucket: Bucket): void {\n const now = Date.now();\n const elapsedMs = now - bucket.lastRefillMs;\n if (elapsedMs <= 0) {\n return;\n }\n\n const refillTokens = (elapsedMs / 1000) * bucket.refillPerSecond;\n bucket.tokens = Math.min(bucket.capacity, bucket.tokens + refillTokens);\n bucket.lastRefillMs = now;\n }\n}\n","import { getNow, signOkxPayload } from \"../utils/signature.js\";\nimport {\n AuthenticationError,\n ConfigError,\n NetworkError,\n OkxApiError,\n} from \"../utils/errors.js\";\nimport { RateLimiter } from \"../utils/rate-limiter.js\";\nimport type { OkxConfig } from \"../config.js\";\nimport type {\n OkxApiResponse,\n QueryParams,\n QueryValue,\n RequestConfig,\n RequestResult,\n} from \"./types.js\";\n\nfunction isDefined(value: unknown): boolean {\n return value !== undefined && value !== null;\n}\n\nfunction extractTraceId(headers: Headers): string | undefined {\n return (\n headers.get(\"x-trace-id\") ??\n headers.get(\"x-request-id\") ??\n headers.get(\"traceid\") ??\n undefined\n );\n}\n\nfunction stringifyQueryValue(value: QueryValue): string {\n if (Array.isArray(value)) {\n return value.map((item) => String(item)).join(\",\");\n }\n return String(value);\n}\n\nfunction buildQueryString(query?: QueryParams): string {\n if (!query) {\n return \"\";\n }\n\n const entries = Object.entries(query).filter(([, value]) => isDefined(value));\n if (entries.length === 0) {\n return \"\";\n }\n\n const params = new URLSearchParams();\n for (const [key, value] of entries) {\n params.set(key, stringifyQueryValue(value));\n }\n return params.toString();\n}\n\nexport class OkxRestClient {\n private readonly config: OkxConfig;\n private readonly rateLimiter = new RateLimiter();\n\n public constructor(config: OkxConfig) {\n this.config = config;\n }\n\n public async publicGet<TData = unknown>(\n path: string,\n query?: QueryParams,\n rateLimit?: RequestConfig[\"rateLimit\"],\n ): Promise<RequestResult<TData>> {\n return this.request<TData>({\n method: \"GET\",\n path,\n auth: \"public\",\n query,\n rateLimit,\n });\n }\n\n public async privateGet<TData = unknown>(\n path: string,\n query?: QueryParams,\n rateLimit?: RequestConfig[\"rateLimit\"],\n ): Promise<RequestResult<TData>> {\n return this.request<TData>({\n method: \"GET\",\n path,\n auth: \"private\",\n query,\n rateLimit,\n });\n }\n\n public async privatePost<TData = unknown>(\n path: string,\n body?: RequestConfig[\"body\"],\n rateLimit?: RequestConfig[\"rateLimit\"],\n ): Promise<RequestResult<TData>> {\n return this.request<TData>({\n method: \"POST\",\n path,\n auth: \"private\",\n body,\n rateLimit,\n });\n }\n\n private async request<TData = unknown>(\n config: RequestConfig,\n ): Promise<RequestResult<TData>> {\n const queryString = buildQueryString(config.query);\n const requestPath = queryString.length > 0 ? `${config.path}?${queryString}` : config.path;\n const url = `${this.config.baseUrl}${requestPath}`;\n const bodyJson = config.body ? JSON.stringify(config.body) : \"\";\n const timestamp = getNow();\n\n if (config.rateLimit) {\n await this.rateLimiter.consume(config.rateLimit);\n }\n\n const headers = new Headers({\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n });\n\n if (this.config.userAgent) {\n headers.set(\"User-Agent\", this.config.userAgent);\n }\n\n if (config.auth === \"private\") {\n if (!this.config.hasAuth) {\n throw new ConfigError(\n \"Private endpoint requires API credentials.\",\n \"Configure OKX_API_KEY, OKX_SECRET_KEY and OKX_PASSPHRASE.\",\n );\n }\n\n if (!this.config.apiKey || !this.config.secretKey || !this.config.passphrase) {\n throw new ConfigError(\n \"Invalid private API credentials state.\",\n \"Ensure all OKX credentials are set.\",\n );\n }\n\n // OKX signature: timestamp + METHOD + requestPath + body\n const payload = `${timestamp}${config.method.toUpperCase()}${requestPath}${bodyJson}`;\n const signature = signOkxPayload(payload, this.config.secretKey);\n headers.set(\"OK-ACCESS-KEY\", this.config.apiKey);\n headers.set(\"OK-ACCESS-SIGN\", signature);\n headers.set(\"OK-ACCESS-PASSPHRASE\", this.config.passphrase);\n headers.set(\"OK-ACCESS-TIMESTAMP\", timestamp);\n }\n\n if (this.config.demo) {\n headers.set(\"x-simulated-trading\", \"1\");\n }\n\n let response: Response;\n try {\n response = await fetch(url, {\n method: config.method,\n headers,\n body: config.method === \"POST\" ? bodyJson : undefined,\n signal: AbortSignal.timeout(this.config.timeoutMs),\n });\n } catch (error) {\n throw new NetworkError(\n `Failed to call OKX endpoint ${config.method} ${requestPath}.`,\n `${config.method} ${requestPath}`,\n error,\n );\n }\n\n const rawText = await response.text();\n const traceId = extractTraceId(response.headers);\n let parsed: OkxApiResponse<TData>;\n try {\n parsed = (rawText ? JSON.parse(rawText) : {}) as OkxApiResponse<TData>;\n } catch (error) {\n if (!response.ok) {\n const messagePreview = rawText.slice(0, 160).replace(/\\s+/g, \" \").trim();\n throw new OkxApiError(\n `HTTP ${response.status} from OKX: ${messagePreview || \"Non-JSON response body\"}`,\n {\n code: String(response.status),\n endpoint: `${config.method} ${config.path}`,\n suggestion: \"Verify endpoint path and request parameters.\",\n traceId,\n },\n );\n }\n throw new NetworkError(\n `OKX returned non-JSON response for ${config.method} ${requestPath}.`,\n `${config.method} ${requestPath}`,\n error,\n );\n }\n\n if (!response.ok) {\n throw new OkxApiError(\n `HTTP ${response.status} from OKX: ${parsed.msg ?? \"Unknown error\"}`,\n {\n code: String(response.status),\n endpoint: `${config.method} ${config.path}`,\n suggestion: \"Retry later or verify endpoint parameters.\",\n traceId,\n },\n );\n }\n\n const responseCode = parsed.code;\n if (responseCode && responseCode !== \"0\") {\n const message = parsed.msg ?? \"OKX API request failed.\";\n if (\n responseCode === \"50111\" ||\n responseCode === \"50112\" ||\n responseCode === \"50113\"\n ) {\n throw new AuthenticationError(\n message,\n \"Check API key, secret, passphrase and permissions.\",\n `${config.method} ${config.path}`,\n traceId,\n );\n }\n\n throw new OkxApiError(message, {\n code: responseCode,\n endpoint: `${config.method} ${config.path}`,\n traceId,\n });\n }\n\n return {\n endpoint: `${config.method} ${config.path}`,\n requestTime: new Date().toISOString(),\n data: (parsed.data ?? null) as TData,\n raw: parsed,\n };\n }\n}\n","import { ValidationError } from \"../utils/errors.js\";\n\nexport function asRecord(value: unknown): Record<string, unknown> {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return {};\n }\n return value as Record<string, unknown>;\n}\n\nexport function readString(\n args: Record<string, unknown>,\n key: string,\n): string | undefined {\n const value = args[key];\n if (value === undefined || value === null) {\n return undefined;\n }\n if (typeof value !== \"string\") {\n throw new ValidationError(`Parameter \"${key}\" must be a string.`);\n }\n return value;\n}\n\nexport function readNumber(\n args: Record<string, unknown>,\n key: string,\n): number | undefined {\n const value = args[key];\n if (value === undefined || value === null) {\n return undefined;\n }\n if (typeof value !== \"number\" || Number.isNaN(value)) {\n throw new ValidationError(`Parameter \"${key}\" must be a number.`);\n }\n return value;\n}\n\nexport function readBoolean(\n args: Record<string, unknown>,\n key: string,\n): boolean | undefined {\n const value = args[key];\n if (value === undefined || value === null) {\n return undefined;\n }\n if (typeof value !== \"boolean\") {\n throw new ValidationError(`Parameter \"${key}\" must be a boolean.`);\n }\n return value;\n}\n\nexport function readStringArray(\n args: Record<string, unknown>,\n key: string,\n): string[] | undefined {\n const value = args[key];\n if (value === undefined || value === null) {\n return undefined;\n }\n if (!Array.isArray(value) || value.some((item) => typeof item !== \"string\")) {\n throw new ValidationError(`Parameter \"${key}\" must be an array of strings.`);\n }\n return value;\n}\n\nexport function requireString(\n args: Record<string, unknown>,\n key: string,\n): string {\n const value = readString(args, key);\n if (!value || value.length === 0) {\n throw new ValidationError(`Missing required parameter \"${key}\".`);\n }\n return value;\n}\n\nexport function assertEnum(\n value: string | undefined,\n key: string,\n values: readonly string[],\n): void {\n if (value === undefined) {\n return;\n }\n if (!values.includes(value)) {\n throw new ValidationError(\n `Parameter \"${key}\" must be one of: ${values.join(\", \")}.`,\n );\n }\n}\n\nexport function compactObject(\n object: Record<string, unknown>,\n): Record<string, unknown> {\n const next: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(object)) {\n if (value !== undefined && value !== null) {\n next[key] = value;\n }\n }\n return next;\n}\n","import type { RateLimitConfig } from \"../utils/rate-limiter.js\";\nimport { ConfigError } from \"../utils/errors.js\";\nimport type { OkxConfig } from \"../config.js\";\n\nexport const OKX_CANDLE_BARS = [\n \"1m\", \"3m\", \"5m\", \"15m\", \"30m\",\n \"1H\", \"2H\", \"4H\", \"6H\", \"12H\",\n \"1D\", \"2D\", \"3D\", \"1W\", \"1M\", \"3M\",\n] as const;\n\nexport const OKX_INST_TYPES = [\n \"SPOT\", \"SWAP\", \"FUTURES\", \"OPTION\", \"MARGIN\",\n] as const;\n\nexport function publicRateLimit(key: string, rps = 20): RateLimitConfig {\n return {\n key: `public:${key}`,\n capacity: rps,\n refillPerSecond: rps,\n };\n}\n\nexport function privateRateLimit(key: string, rps = 10): RateLimitConfig {\n return {\n key: `private:${key}`,\n capacity: rps,\n refillPerSecond: rps,\n };\n}\n\n/**\n * Throw a ConfigError if demo/simulated trading mode is active.\n * Use this for endpoints that OKX does not support in simulated trading.\n */\nexport function assertNotDemo(config: OkxConfig, endpoint: string): void {\n if (config.demo) {\n throw new ConfigError(\n `\"${endpoint}\" is not supported in simulated trading mode.`,\n \"Disable demo mode (remove OKX_DEMO=1 or --demo flag) to use this endpoint.\",\n );\n }\n}\n","import type { ToolSpec } from \"./types.js\";\nimport {\n asRecord,\n compactObject,\n readBoolean,\n readNumber,\n readString,\n requireString,\n} from \"./helpers.js\";\nimport { privateRateLimit } from \"./common.js\";\n\nfunction normalize(response: {\n endpoint: string;\n requestTime: string;\n data: unknown;\n}): Record<string, unknown> {\n return {\n endpoint: response.endpoint,\n requestTime: response.requestTime,\n data: response.data,\n };\n}\n\nexport function registerAccountTools(): ToolSpec[] {\n return [\n {\n name: \"account_get_balance\",\n module: \"account\",\n description:\n \"Get account balance for trading account. Returns balances for all currencies or a specific one. Private endpoint. Rate limit: 10 req/s.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n ccy: {\n type: \"string\",\n description:\n \"Currency, e.g. BTC. Comma-separated for multiple, e.g. BTC,ETH. Omit for all.\",\n },\n },\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.privateGet(\n \"/api/v5/account/balance\",\n compactObject({ ccy: readString(args, \"ccy\") }),\n privateRateLimit(\"account_get_balance\", 10),\n );\n return normalize(response);\n },\n },\n {\n name: \"account_transfer\",\n module: \"account\",\n description:\n \"Transfer funds between accounts (trading, funding, etc.). [CAUTION] Moves real funds. Private endpoint. Rate limit: 2 req/s.\",\n isWrite: true,\n inputSchema: {\n type: \"object\",\n properties: {\n ccy: {\n type: \"string\",\n description: \"Currency to transfer, e.g. USDT.\",\n },\n amt: {\n type: \"string\",\n description: \"Transfer amount.\",\n },\n from: {\n type: \"string\",\n description:\n \"Transfer source account type. 6=funding, 18=trading (unified).\",\n },\n to: {\n type: \"string\",\n description:\n \"Transfer destination account type. 6=funding, 18=trading (unified).\",\n },\n type: {\n type: \"string\",\n description:\n \"Transfer type. 0=master account transfer (default), 1=master to sub-account, 2=sub-account to master, 3=sub-account to sub-account.\",\n },\n subAcct: {\n type: \"string\",\n description: \"Sub-account name. Required when type is 1, 2, or 3.\",\n },\n clientId: {\n type: \"string\",\n description: \"Client-supplied ID. Up to 32 characters.\",\n },\n },\n required: [\"ccy\", \"amt\", \"from\", \"to\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.privatePost(\n \"/api/v5/asset/transfer\",\n compactObject({\n ccy: requireString(args, \"ccy\"),\n amt: requireString(args, \"amt\"),\n from: requireString(args, \"from\"),\n to: requireString(args, \"to\"),\n type: readString(args, \"type\"),\n subAcct: readString(args, \"subAcct\"),\n clientId: readString(args, \"clientId\"),\n }),\n privateRateLimit(\"account_transfer\", 2),\n );\n return normalize(response);\n },\n },\n {\n name: \"account_get_max_size\",\n module: \"account\",\n description:\n \"Get max buy/sell order size for a SWAP/FUTURES instrument given current balance and leverage. Useful before placing orders. Private. Rate limit: 20 req/s.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n instId: {\n type: \"string\",\n description: \"Instrument ID, e.g. BTC-USDT-SWAP.\",\n },\n tdMode: {\n type: \"string\",\n enum: [\"cross\", \"isolated\"],\n description: \"Trade mode: cross or isolated margin.\",\n },\n px: {\n type: \"string\",\n description:\n \"Order price for limit order calculation. Affects the max size result. Omit for market orders.\",\n },\n leverage: {\n type: \"string\",\n description: \"Leverage to use for calculation. Defaults to current account leverage.\",\n },\n ccy: {\n type: \"string\",\n description: \"Margin currency. Required for isolated margin mode.\",\n },\n },\n required: [\"instId\", \"tdMode\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.privateGet(\n \"/api/v5/account/max-size\",\n compactObject({\n instId: requireString(args, \"instId\"),\n tdMode: requireString(args, \"tdMode\"),\n px: readString(args, \"px\"),\n leverage: readString(args, \"leverage\"),\n ccy: readString(args, \"ccy\"),\n }),\n privateRateLimit(\"account_get_max_size\", 20),\n );\n return normalize(response);\n },\n },\n {\n name: \"account_get_asset_balance\",\n module: \"account\",\n description:\n \"Get funding account balance (asset account). Different from account_get_balance which queries the trading account. Private. Rate limit: 6 req/s.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n ccy: {\n type: \"string\",\n description:\n \"Currency filter, e.g. BTC or BTC,ETH for multiple. Omit to return all currencies.\",\n },\n },\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.privateGet(\n \"/api/v5/asset/balances\",\n compactObject({ ccy: readString(args, \"ccy\") }),\n privateRateLimit(\"account_get_asset_balance\", 6),\n );\n return normalize(response);\n },\n },\n {\n name: \"account_get_bills\",\n module: \"account\",\n description:\n \"Get account ledger: fees paid, funding charges, realized PnL, transfers, etc. \" +\n \"Default 20 records (last 7 days), max 100. Private endpoint. Rate limit: 6 req/s.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n instType: {\n type: \"string\",\n enum: [\"SPOT\", \"MARGIN\", \"SWAP\", \"FUTURES\", \"OPTION\"],\n description: \"Filter by instrument type.\",\n },\n ccy: {\n type: \"string\",\n description: \"Currency filter, e.g. USDT.\",\n },\n mgnMode: {\n type: \"string\",\n enum: [\"isolated\", \"cross\"],\n description: \"Margin mode filter.\",\n },\n type: {\n type: \"string\",\n description:\n \"Bill type filter. 1=transfer, 2=trade, 3=delivery, 4=auto token convert, 5=liquidation, 6=margin transfer, 7=interest deduction, 8=funding fee, 9=adl, 10=clawback, 11=system token convert, 12=strategy transfer, 13=ddh.\",\n },\n after: {\n type: \"string\",\n description: \"Pagination: records earlier than this bill ID.\",\n },\n before: {\n type: \"string\",\n description: \"Pagination: records newer than this bill ID.\",\n },\n begin: {\n type: \"string\",\n description: \"Start time in milliseconds.\",\n },\n end: {\n type: \"string\",\n description: \"End time in milliseconds.\",\n },\n limit: {\n type: \"number\",\n description: \"Number of results. Default 20, max 100.\",\n },\n },\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.privateGet(\n \"/api/v5/account/bills\",\n compactObject({\n instType: readString(args, \"instType\"),\n ccy: readString(args, \"ccy\"),\n mgnMode: readString(args, \"mgnMode\"),\n type: readString(args, \"type\"),\n after: readString(args, \"after\"),\n before: readString(args, \"before\"),\n begin: readString(args, \"begin\"),\n end: readString(args, \"end\"),\n limit: readNumber(args, \"limit\") ?? 20,\n }),\n privateRateLimit(\"account_get_bills\", 6),\n );\n return normalize(response);\n },\n },\n {\n name: \"account_get_positions_history\",\n module: \"account\",\n description:\n \"Get closed position history for SWAP or FUTURES. \" +\n \"Default 20 records, max 100. Private endpoint. Rate limit: 1 req/s.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n instType: {\n type: \"string\",\n enum: [\"SWAP\", \"FUTURES\", \"MARGIN\", \"OPTION\"],\n description: \"Instrument type filter. Default SWAP.\",\n },\n instId: {\n type: \"string\",\n description: \"Instrument ID filter, e.g. BTC-USDT-SWAP.\",\n },\n mgnMode: {\n type: \"string\",\n enum: [\"cross\", \"isolated\"],\n description: \"Margin mode filter.\",\n },\n type: {\n type: \"string\",\n description: \"Close type filter. 1=close long, 2=close short, 3=liquidation long, 4=liquidation short, 5=ADL long, 6=ADL short.\",\n },\n posId: {\n type: \"string\",\n description: \"Position ID filter.\",\n },\n after: {\n type: \"string\",\n description: \"Pagination: records earlier than this timestamp (ms).\",\n },\n before: {\n type: \"string\",\n description: \"Pagination: records newer than this timestamp (ms).\",\n },\n limit: {\n type: \"number\",\n description: \"Number of results. Default 20, max 100.\",\n },\n },\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.privateGet(\n \"/api/v5/account/positions-history\",\n compactObject({\n instType: readString(args, \"instType\") ?? \"SWAP\",\n instId: readString(args, \"instId\"),\n mgnMode: readString(args, \"mgnMode\"),\n type: readString(args, \"type\"),\n posId: readString(args, \"posId\"),\n after: readString(args, \"after\"),\n before: readString(args, \"before\"),\n limit: readNumber(args, \"limit\") ?? 20,\n }),\n privateRateLimit(\"account_get_positions_history\", 1),\n );\n return normalize(response);\n },\n },\n {\n name: \"account_get_trade_fee\",\n module: \"account\",\n description:\n \"Get maker/taker fee rates for the account. Useful to understand your fee tier before trading. Private endpoint. Rate limit: 5 req/s.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n instType: {\n type: \"string\",\n enum: [\"SPOT\", \"MARGIN\", \"SWAP\", \"FUTURES\", \"OPTION\"],\n description: \"Instrument type to query fee tier for.\",\n },\n instId: {\n type: \"string\",\n description: \"Instrument ID for instrument-specific fee. Optional.\",\n },\n },\n required: [\"instType\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.privateGet(\n \"/api/v5/account/trade-fee\",\n compactObject({\n instType: requireString(args, \"instType\"),\n instId: readString(args, \"instId\"),\n }),\n privateRateLimit(\"account_get_trade_fee\", 5),\n );\n return normalize(response);\n },\n },\n {\n name: \"account_get_config\",\n module: \"account\",\n description:\n \"Get account configuration: position mode (net vs hedge), account level, auto-loan settings, etc. Private endpoint. Rate limit: 5 req/s.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {},\n },\n handler: async (_rawArgs, context) => {\n const response = await context.client.privateGet(\n \"/api/v5/account/config\",\n {},\n privateRateLimit(\"account_get_config\", 5),\n );\n return normalize(response);\n },\n },\n {\n name: \"account_get_max_withdrawal\",\n module: \"account\",\n description:\n \"Get maximum withdrawable amount for a currency from the trading account. \" +\n \"Useful before initiating a transfer or withdrawal. Private endpoint. Rate limit: 20 req/s.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n ccy: {\n type: \"string\",\n description:\n \"Currency to query, e.g. USDT. Comma-separated for multiple, e.g. BTC,ETH. Omit for all.\",\n },\n },\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.privateGet(\n \"/api/v5/account/max-withdrawal\",\n compactObject({ ccy: readString(args, \"ccy\") }),\n privateRateLimit(\"account_get_max_withdrawal\", 20),\n );\n return normalize(response);\n },\n },\n {\n name: \"account_get_max_avail_size\",\n module: \"account\",\n description:\n \"Get maximum available size for opening or reducing a position. \" +\n \"Different from account_get_max_size which calculates new order size. \" +\n \"Private endpoint. Rate limit: 20 req/s.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n instId: {\n type: \"string\",\n description: \"Instrument ID, e.g. BTC-USDT-SWAP or BTC-USDT.\",\n },\n tdMode: {\n type: \"string\",\n enum: [\"cross\", \"isolated\", \"cash\"],\n description: \"Trade mode: cross, isolated, or cash (spot).\",\n },\n ccy: {\n type: \"string\",\n description: \"Margin currency. Required for isolated MARGIN mode.\",\n },\n reduceOnly: {\n type: \"boolean\",\n description: \"Set true to calculate max size for closing/reducing a position.\",\n },\n },\n required: [\"instId\", \"tdMode\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const reduceOnly = readBoolean(args, \"reduceOnly\");\n const response = await context.client.privateGet(\n \"/api/v5/account/max-avail-size\",\n compactObject({\n instId: requireString(args, \"instId\"),\n tdMode: requireString(args, \"tdMode\"),\n ccy: readString(args, \"ccy\"),\n reduceOnly: reduceOnly !== undefined ? String(reduceOnly) : undefined,\n }),\n privateRateLimit(\"account_get_max_avail_size\", 20),\n );\n return normalize(response);\n },\n },\n {\n name: \"account_get_positions\",\n module: \"account\",\n description:\n \"Get current open positions across all instrument types (MARGIN, SWAP, FUTURES, OPTION). \" +\n \"Use swap_get_positions for SWAP/FUTURES-only queries when the swap module is loaded. \" +\n \"Private endpoint. Rate limit: 10 req/s.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n instType: {\n type: \"string\",\n enum: [\"MARGIN\", \"SWAP\", \"FUTURES\", \"OPTION\"],\n description: \"Filter by instrument type. Omit to return all open positions.\",\n },\n instId: {\n type: \"string\",\n description: \"Instrument ID filter, e.g. BTC-USDT-SWAP. Omit for all instruments.\",\n },\n posId: {\n type: \"string\",\n description: \"Position ID filter.\",\n },\n },\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.privateGet(\n \"/api/v5/account/positions\",\n compactObject({\n instType: readString(args, \"instType\"),\n instId: readString(args, \"instId\"),\n posId: readString(args, \"posId\"),\n }),\n privateRateLimit(\"account_get_positions\", 10),\n );\n return normalize(response);\n },\n },\n {\n name: \"account_get_bills_archive\",\n module: \"account\",\n description:\n \"Get archived account ledger (bills older than 7 days, up to 3 months). \" +\n \"Use account_get_bills for recent 7-day records. \" +\n \"Default 20 records, max 100. Private endpoint. Rate limit: 6 req/s.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n instType: {\n type: \"string\",\n enum: [\"SPOT\", \"MARGIN\", \"SWAP\", \"FUTURES\", \"OPTION\"],\n description: \"Filter by instrument type.\",\n },\n ccy: {\n type: \"string\",\n description: \"Currency filter, e.g. USDT.\",\n },\n mgnMode: {\n type: \"string\",\n enum: [\"isolated\", \"cross\"],\n description: \"Margin mode filter.\",\n },\n type: {\n type: \"string\",\n description:\n \"Bill type filter. 1=transfer, 2=trade, 3=delivery, 4=auto token convert, 5=liquidation, 6=margin transfer, 7=interest deduction, 8=funding fee, 9=adl, 10=clawback, 11=system token convert, 12=strategy transfer, 13=ddh.\",\n },\n after: {\n type: \"string\",\n description: \"Pagination: records earlier than this bill ID.\",\n },\n before: {\n type: \"string\",\n description: \"Pagination: records newer than this bill ID.\",\n },\n begin: {\n type: \"string\",\n description: \"Start time in milliseconds.\",\n },\n end: {\n type: \"string\",\n description: \"End time in milliseconds.\",\n },\n limit: {\n type: \"number\",\n description: \"Number of results. Default 20, max 100.\",\n },\n },\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.privateGet(\n \"/api/v5/account/bills-archive\",\n compactObject({\n instType: readString(args, \"instType\"),\n ccy: readString(args, \"ccy\"),\n mgnMode: readString(args, \"mgnMode\"),\n type: readString(args, \"type\"),\n after: readString(args, \"after\"),\n before: readString(args, \"before\"),\n begin: readString(args, \"begin\"),\n end: readString(args, \"end\"),\n limit: readNumber(args, \"limit\") ?? 20,\n }),\n privateRateLimit(\"account_get_bills_archive\", 6),\n );\n return normalize(response);\n },\n },\n {\n name: \"account_set_position_mode\",\n module: \"account\",\n description:\n \"Switch between net position mode and long/short hedge mode. \" +\n \"net: one position per instrument (default for most accounts). \" +\n \"long_short_mode: separate long and short positions. \" +\n \"[CAUTION] Requires no open positions or pending orders. Private endpoint. Rate limit: 5 req/s.\",\n isWrite: true,\n inputSchema: {\n type: \"object\",\n properties: {\n posMode: {\n type: \"string\",\n enum: [\"long_short_mode\", \"net_mode\"],\n description: \"Position mode: 'long_short_mode' for hedge mode, 'net_mode' for one-way mode.\",\n },\n },\n required: [\"posMode\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.privatePost(\n \"/api/v5/account/set-position-mode\",\n { posMode: requireString(args, \"posMode\") },\n privateRateLimit(\"account_set_position_mode\", 5),\n );\n return normalize(response);\n },\n },\n ];\n}\n","import type { ToolSpec } from \"./types.js\";\nimport {\n asRecord,\n compactObject,\n readNumber,\n readString,\n requireString,\n} from \"./helpers.js\";\nimport { privateRateLimit } from \"./common.js\";\n\nfunction normalize(response: {\n endpoint: string;\n requestTime: string;\n data: unknown;\n}): Record<string, unknown> {\n return {\n endpoint: response.endpoint,\n requestTime: response.requestTime,\n data: response.data,\n };\n}\n\nexport function registerAlgoTradeTools(): ToolSpec[] {\n return [\n {\n name: \"swap_place_algo_order\",\n module: \"swap\",\n description:\n \"Place a SWAP/FUTURES take-profit or stop-loss algo order. [CAUTION] Executes real trades. \" +\n \"Use ordType='conditional' for a single TP, single SL, or combined TP+SL on one order. \" +\n \"Use ordType='oco' (one-cancels-other) to place TP and SL simultaneously — whichever triggers first cancels the other. \" +\n \"Set tpOrdPx='-1' or slOrdPx='-1' to execute the closing leg as a market order. \" +\n \"Private endpoint. Rate limit: 20 req/s per UID.\",\n isWrite: true,\n inputSchema: {\n type: \"object\",\n properties: {\n instId: {\n type: \"string\",\n description: \"Instrument ID, e.g. BTC-USDT-SWAP.\",\n },\n tdMode: {\n type: \"string\",\n enum: [\"cross\", \"isolated\"],\n description: \"Trade mode: cross or isolated margin.\",\n },\n side: {\n type: \"string\",\n enum: [\"buy\", \"sell\"],\n description:\n \"Closing side: use 'sell' to close a long position, 'buy' to close a short position.\",\n },\n posSide: {\n type: \"string\",\n enum: [\"long\", \"short\", \"net\"],\n description:\n \"Position side. Use 'net' for one-way mode (default for most accounts). Use 'long' or 'short' only in hedge mode.\",\n },\n ordType: {\n type: \"string\",\n enum: [\"conditional\", \"oco\"],\n description:\n \"Algo order type. 'conditional': set TP only, SL only, or both TP+SL together. 'oco': set TP and SL as a pair — the first to trigger cancels the other.\",\n },\n sz: {\n type: \"string\",\n description:\n \"Number of contracts to close (e.g. '1'). Should match your open position size.\",\n },\n tpTriggerPx: {\n type: \"string\",\n description:\n \"Take-profit trigger price. When market reaches this price, the TP order is submitted. Required if setting a take-profit.\",\n },\n tpOrdPx: {\n type: \"string\",\n description:\n \"Take-profit order price. Set to '-1' for a market order when triggered. Required if tpTriggerPx is set.\",\n },\n tpTriggerPxType: {\n type: \"string\",\n enum: [\"last\", \"index\", \"mark\"],\n description:\n \"Price type for tpTriggerPx. 'last': last traded price (default). 'index': index price. 'mark': mark price.\",\n },\n slTriggerPx: {\n type: \"string\",\n description:\n \"Stop-loss trigger price. When market reaches this price, the SL order is submitted. Required if setting a stop-loss.\",\n },\n slOrdPx: {\n type: \"string\",\n description:\n \"Stop-loss order price. Set to '-1' for a market order when triggered (recommended to ensure execution). Required if slTriggerPx is set.\",\n },\n slTriggerPxType: {\n type: \"string\",\n enum: [\"last\", \"index\", \"mark\"],\n description:\n \"Price type for slTriggerPx. 'last': last traded price (default). 'index': index price. 'mark': mark price.\",\n },\n reduceOnly: {\n type: \"boolean\",\n description:\n \"Set true to ensure this order only reduces an existing position. Recommended for TP/SL orders.\",\n },\n clOrdId: {\n type: \"string\",\n description: \"Client-supplied order ID. Up to 32 characters.\",\n },\n },\n required: [\"instId\", \"tdMode\", \"side\", \"ordType\", \"sz\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const reduceOnly = args.reduceOnly;\n const response = await context.client.privatePost(\n \"/api/v5/trade/order-algo\",\n compactObject({\n instId: requireString(args, \"instId\"),\n tdMode: requireString(args, \"tdMode\"),\n side: requireString(args, \"side\"),\n posSide: readString(args, \"posSide\"),\n ordType: requireString(args, \"ordType\"),\n sz: requireString(args, \"sz\"),\n tpTriggerPx: readString(args, \"tpTriggerPx\"),\n tpOrdPx: readString(args, \"tpOrdPx\"),\n tpTriggerPxType: readString(args, \"tpTriggerPxType\"),\n slTriggerPx: readString(args, \"slTriggerPx\"),\n slOrdPx: readString(args, \"slOrdPx\"),\n slTriggerPxType: readString(args, \"slTriggerPxType\"),\n reduceOnly:\n typeof reduceOnly === \"boolean\" ? String(reduceOnly) : undefined,\n clOrdId: readString(args, \"clOrdId\"),\n }),\n privateRateLimit(\"swap_place_algo_order\", 20),\n );\n return normalize(response);\n },\n },\n {\n name: \"swap_place_move_stop_order\",\n module: \"swap\",\n description:\n \"Place a SWAP/FUTURES trailing stop order (move_order_stop). [CAUTION] Executes real trades. \" +\n \"The order tracks the market price and triggers when the price reverses by the callback amount. \" +\n \"Specify either callbackRatio (e.g. '0.01' for 1%) or callbackSpread (fixed price distance), not both. \" +\n \"Optionally set activePx so tracking only starts once the market reaches that price. \" +\n \"Private endpoint. Rate limit: 20 req/s per UID.\",\n isWrite: true,\n inputSchema: {\n type: \"object\",\n properties: {\n instId: {\n type: \"string\",\n description: \"Instrument ID, e.g. BTC-USDT-SWAP.\",\n },\n tdMode: {\n type: \"string\",\n enum: [\"cross\", \"isolated\"],\n description: \"Trade mode: cross or isolated margin.\",\n },\n side: {\n type: \"string\",\n enum: [\"buy\", \"sell\"],\n description:\n \"Closing side: use 'sell' to close a long position, 'buy' to close a short position.\",\n },\n posSide: {\n type: \"string\",\n enum: [\"long\", \"short\", \"net\"],\n description:\n \"Position side. Use 'net' for one-way mode (default). Use 'long' or 'short' only in hedge mode.\",\n },\n sz: {\n type: \"string\",\n description: \"Number of contracts (e.g. '1').\",\n },\n callbackRatio: {\n type: \"string\",\n description:\n \"Callback ratio as a decimal (e.g. '0.01' for 1%). Provide either callbackRatio or callbackSpread, not both.\",\n },\n callbackSpread: {\n type: \"string\",\n description:\n \"Callback spread in quote-currency price units. Provide either callbackRatio or callbackSpread, not both.\",\n },\n activePx: {\n type: \"string\",\n description:\n \"Optional activation price. Trailing only starts after the market reaches this level.\",\n },\n reduceOnly: {\n type: \"boolean\",\n description: \"Set true to ensure the order only reduces an existing position.\",\n },\n clOrdId: {\n type: \"string\",\n description: \"Client-supplied order ID. Up to 32 characters.\",\n },\n },\n required: [\"instId\", \"tdMode\", \"side\", \"sz\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const reduceOnly = args.reduceOnly;\n const response = await context.client.privatePost(\n \"/api/v5/trade/order-algo\",\n compactObject({\n instId: requireString(args, \"instId\"),\n tdMode: requireString(args, \"tdMode\"),\n side: requireString(args, \"side\"),\n posSide: readString(args, \"posSide\"),\n ordType: \"move_order_stop\",\n sz: requireString(args, \"sz\"),\n callbackRatio: readString(args, \"callbackRatio\"),\n callbackSpread: readString(args, \"callbackSpread\"),\n activePx: readString(args, \"activePx\"),\n reduceOnly:\n typeof reduceOnly === \"boolean\" ? String(reduceOnly) : undefined,\n clOrdId: readString(args, \"clOrdId\"),\n }),\n privateRateLimit(\"swap_place_move_stop_order\", 20),\n );\n return normalize(response);\n },\n },\n {\n name: \"swap_cancel_algo_orders\",\n module: \"swap\",\n description:\n \"Cancel one or more pending SWAP/FUTURES algo orders (TP/SL). \" +\n \"Accepts a list of {algoId, instId} objects. Private endpoint. Rate limit: 20 req/s per UID.\",\n isWrite: true,\n inputSchema: {\n type: \"object\",\n properties: {\n orders: {\n type: \"array\",\n description:\n \"List of algo orders to cancel. Each item must have algoId and instId.\",\n items: {\n type: \"object\",\n properties: {\n algoId: {\n type: \"string\",\n description: \"Algo order ID to cancel.\",\n },\n instId: {\n type: \"string\",\n description: \"Instrument ID, e.g. BTC-USDT-SWAP.\",\n },\n },\n required: [\"algoId\", \"instId\"],\n },\n },\n },\n required: [\"orders\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const orders = args.orders;\n if (!Array.isArray(orders) || orders.length === 0) {\n throw new Error(\"orders must be a non-empty array.\");\n }\n const response = await context.client.privatePost(\n \"/api/v5/trade/cancel-algos\",\n orders,\n privateRateLimit(\"swap_cancel_algo_orders\", 20),\n );\n return normalize(response);\n },\n },\n {\n name: \"swap_get_algo_orders\",\n module: \"swap\",\n description:\n \"Query pending or completed SWAP/FUTURES algo orders (TP/SL, OCO, trailing stop). Private endpoint. Rate limit: 20 req/s.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n status: {\n type: \"string\",\n enum: [\"pending\", \"history\"],\n description:\n \"Query pending (active) algo orders or completed history. Default: 'pending'.\",\n },\n ordType: {\n type: \"string\",\n enum: [\"conditional\", \"oco\", \"move_order_stop\"],\n description:\n \"Filter by algo order type. Omit to return all types (conditional + oco + move_order_stop).\",\n },\n instId: {\n type: \"string\",\n description: \"Instrument ID filter, e.g. BTC-USDT-SWAP.\",\n },\n algoId: {\n type: \"string\",\n description: \"Filter by specific algo order ID.\",\n },\n after: {\n type: \"string\",\n description: \"Pagination: orders earlier than this algo order ID.\",\n },\n before: {\n type: \"string\",\n description: \"Pagination: orders newer than this algo order ID.\",\n },\n limit: {\n type: \"number\",\n description: \"Number of results, default 100, max 100.\",\n },\n },\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const status = readString(args, \"status\") ?? \"pending\";\n const path =\n status === \"history\"\n ? \"/api/v5/trade/orders-algo-history\"\n : \"/api/v5/trade/orders-algo-pending\";\n const ordType = readString(args, \"ordType\");\n const baseParams = compactObject({\n instType: \"SWAP\",\n instId: readString(args, \"instId\"),\n algoId: readString(args, \"algoId\"),\n after: readString(args, \"after\"),\n before: readString(args, \"before\"),\n limit: readNumber(args, \"limit\"),\n });\n\n if (ordType) {\n const response = await context.client.privateGet(\n path,\n { ...baseParams, ordType },\n privateRateLimit(\"swap_get_algo_orders\", 20),\n );\n return normalize(response);\n }\n\n // No filter: fetch all three types in parallel and merge\n const [r1, r2, r3] = await Promise.all([\n context.client.privateGet(path, { ...baseParams, ordType: \"conditional\" }, privateRateLimit(\"swap_get_algo_orders\", 20)),\n context.client.privateGet(path, { ...baseParams, ordType: \"oco\" }, privateRateLimit(\"swap_get_algo_orders\", 20)),\n context.client.privateGet(path, { ...baseParams, ordType: \"move_order_stop\" }, privateRateLimit(\"swap_get_algo_orders\", 20)),\n ]);\n const merged = [\n ...((r1.data as unknown[]) ?? []),\n ...((r2.data as unknown[]) ?? []),\n ...((r3.data as unknown[]) ?? []),\n ];\n return { endpoint: r1.endpoint, requestTime: r1.requestTime, data: merged };\n },\n },\n ];\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport os from \"node:os\";\nimport type { ToolSpec } from \"./types.js\";\nimport { asRecord, readNumber, readString } from \"./helpers.js\";\nimport type { LogEntry } from \"../utils/logger.js\";\n\nconst DEFAULT_LOG_DIR = path.join(os.homedir(), \".okx\", \"logs\");\n\nfunction getLogPaths(logDir: string, days = 7): string[] {\n const paths: string[] = [];\n const now = new Date();\n for (let i = 0; i < days; i++) {\n const d = new Date(now);\n d.setUTCDate(now.getUTCDate() - i);\n const yyyy = d.getUTCFullYear();\n const mm = String(d.getUTCMonth() + 1).padStart(2, \"0\");\n const dd = String(d.getUTCDate()).padStart(2, \"0\");\n paths.push(path.join(logDir, `trade-${yyyy}-${mm}-${dd}.log`));\n }\n return paths;\n}\n\nfunction readEntries(logDir: string): LogEntry[] {\n const entries: LogEntry[] = [];\n for (const filePath of getLogPaths(logDir)) {\n let content: string;\n try {\n content = fs.readFileSync(filePath, \"utf8\");\n } catch {\n continue;\n }\n for (const line of content.split(\"\\n\")) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n try {\n entries.push(JSON.parse(trimmed) as LogEntry);\n } catch {\n // skip malformed lines\n }\n }\n }\n return entries;\n}\n\nexport function registerAuditTools(): ToolSpec[] {\n return [\n {\n name: \"trade_get_history\",\n module: \"account\",\n description:\n \"Query local audit log of tool calls made through this MCP server. \" +\n \"Returns recent operations with timestamps, duration, params, and results. \" +\n \"Use to review what trades or queries were executed in this session or past sessions.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n limit: {\n type: \"number\",\n description: \"Maximum number of entries to return. Default 20, max 100.\",\n },\n tool: {\n type: \"string\",\n description: \"Filter by tool name, e.g. swap_place_order.\",\n },\n level: {\n type: \"string\",\n enum: [\"INFO\", \"WARN\", \"ERROR\", \"DEBUG\"],\n description: \"Filter by log level.\",\n },\n since: {\n type: \"string\",\n description: \"Return entries at or after this ISO 8601 timestamp.\",\n },\n },\n },\n handler: async (rawArgs) => {\n const args = asRecord(rawArgs);\n const limit = Math.min(readNumber(args, \"limit\") ?? 20, 100);\n const toolFilter = readString(args, \"tool\");\n const levelFilter = readString(args, \"level\")?.toUpperCase();\n const since = readString(args, \"since\");\n const sinceTime = since ? new Date(since).getTime() : undefined;\n\n let entries = readEntries(DEFAULT_LOG_DIR);\n\n if (toolFilter) {\n entries = entries.filter((e) => e.tool === toolFilter);\n }\n if (levelFilter) {\n entries = entries.filter((e) => e.level === levelFilter);\n }\n if (sinceTime !== undefined) {\n entries = entries.filter((e) => new Date(e.timestamp).getTime() >= sinceTime);\n }\n\n // most recent first\n entries.sort(\n (a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime(),\n );\n entries = entries.slice(0, limit);\n\n return { entries, total: entries.length };\n },\n },\n ];\n}\n","import type { ToolSpec } from \"../types.js\";\nimport {\n asRecord,\n compactObject,\n readNumber,\n readString,\n requireString,\n} from \"../helpers.js\";\nimport { privateRateLimit } from \"../common.js\";\n\nfunction normalize(response: {\n endpoint: string;\n requestTime: string;\n data: unknown;\n}): Record<string, unknown> {\n return {\n endpoint: response.endpoint,\n requestTime: response.requestTime,\n data: response.data,\n };\n}\n\nexport function registerGridTools(): ToolSpec[] {\n return [\n {\n name: \"grid_get_orders\",\n module: \"bot\",\n description:\n \"Query grid trading bot list. Use status='active' for running bots, status='history' for completed/stopped bots. \" +\n \"Covers Spot Grid, Contract Grid, and Moon Grid. Private endpoint. Rate limit: 20 req/2s per UID.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n algoOrdType: {\n type: \"string\",\n enum: [\"grid\", \"contract_grid\", \"moon_grid\"],\n description:\n \"Grid type. 'grid': Spot Grid. 'contract_grid': Contract Grid. 'moon_grid': Moon Grid.\",\n },\n status: {\n type: \"string\",\n enum: [\"active\", \"history\"],\n description:\n \"Query active (running) bots or history (stopped/completed). Default: 'active'.\",\n },\n instId: {\n type: \"string\",\n description: \"Instrument ID filter, e.g. 'BTC-USDT'.\",\n },\n algoId: {\n type: \"string\",\n description: \"Filter by specific bot algo ID.\",\n },\n after: {\n type: \"string\",\n description: \"Pagination: bots created earlier than this algo ID.\",\n },\n before: {\n type: \"string\",\n description: \"Pagination: bots created later than this algo ID.\",\n },\n limit: {\n type: \"number\",\n description: \"Number of results, default 100, max 100.\",\n },\n },\n required: [\"algoOrdType\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const algoOrdType = requireString(args, \"algoOrdType\");\n const status = readString(args, \"status\") ?? \"active\";\n const path =\n status === \"history\"\n ? \"/api/v5/tradingBot/grid/orders-algo-history\"\n : \"/api/v5/tradingBot/grid/orders-algo-pending\";\n const response = await context.client.privateGet(\n path,\n compactObject({\n algoOrdType,\n instId: readString(args, \"instId\"),\n algoId: readString(args, \"algoId\"),\n after: readString(args, \"after\"),\n before: readString(args, \"before\"),\n limit: readNumber(args, \"limit\"),\n }),\n privateRateLimit(\"grid_get_orders\", 20),\n );\n return normalize(response);\n },\n },\n {\n name: \"grid_get_order_details\",\n module: \"bot\",\n description:\n \"Query details of a single grid trading bot by its algo ID. \" +\n \"Returns configuration, current status, PnL, and position info. \" +\n \"Private endpoint. Rate limit: 20 req/2s per UID.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n algoOrdType: {\n type: \"string\",\n enum: [\"grid\", \"contract_grid\", \"moon_grid\"],\n description: \"Grid type of the bot.\",\n },\n algoId: {\n type: \"string\",\n description: \"Bot algo ID to query.\",\n },\n },\n required: [\"algoOrdType\", \"algoId\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.privateGet(\n \"/api/v5/tradingBot/grid/orders-algo-details\",\n {\n algoOrdType: requireString(args, \"algoOrdType\"),\n algoId: requireString(args, \"algoId\"),\n },\n privateRateLimit(\"grid_get_order_details\", 20),\n );\n return normalize(response);\n },\n },\n {\n name: \"grid_get_sub_orders\",\n module: \"bot\",\n description:\n \"Query individual sub-orders (grid trades) generated by a grid bot. \" +\n \"Use type='filled' for executed trades, type='live' for pending orders. \" +\n \"Private endpoint. Rate limit: 20 req/2s per UID.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n algoOrdType: {\n type: \"string\",\n enum: [\"grid\", \"contract_grid\", \"moon_grid\"],\n description: \"Grid type of the bot.\",\n },\n algoId: {\n type: \"string\",\n description: \"Bot algo ID whose sub-orders to query.\",\n },\n type: {\n type: \"string\",\n enum: [\"filled\", \"live\"],\n description:\n \"Sub-order type. 'filled': executed grid trades. 'live': pending open orders. Default: 'filled'.\",\n },\n groupId: {\n type: \"string\",\n description: \"Filter by sub-order group ID.\",\n },\n after: {\n type: \"string\",\n description: \"Pagination: sub-orders earlier than this order ID.\",\n },\n before: {\n type: \"string\",\n description: \"Pagination: sub-orders newer than this order ID.\",\n },\n limit: {\n type: \"number\",\n description: \"Number of results, default 100, max 100.\",\n },\n },\n required: [\"algoOrdType\", \"algoId\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.privateGet(\n \"/api/v5/tradingBot/grid/sub-orders\",\n compactObject({\n algoOrdType: requireString(args, \"algoOrdType\"),\n algoId: requireString(args, \"algoId\"),\n type: readString(args, \"type\") ?? \"filled\",\n groupId: readString(args, \"groupId\"),\n after: readString(args, \"after\"),\n before: readString(args, \"before\"),\n limit: readNumber(args, \"limit\"),\n }),\n privateRateLimit(\"grid_get_sub_orders\", 20),\n );\n return normalize(response);\n },\n },\n {\n name: \"grid_create_order\",\n module: \"bot\",\n description:\n \"Create a new grid trading bot. [CAUTION] Executes real trades and locks funds. \" +\n \"Supports Spot Grid ('grid') and Contract Grid ('contract_grid'). \" +\n \"For spot grid, provide quoteSz (invest in quote currency) or baseSz (invest in base currency). \" +\n \"For contract grids, provide direction, lever, and sz (number of contracts). \" +\n \"Private endpoint. Rate limit: 20 req/2s per UID.\",\n isWrite: true,\n inputSchema: {\n type: \"object\",\n properties: {\n instId: {\n type: \"string\",\n description: \"Instrument ID, e.g. 'BTC-USDT'.\",\n },\n algoOrdType: {\n type: \"string\",\n enum: [\"grid\", \"contract_grid\"],\n description:\n \"Grid type. 'grid': Spot Grid. 'contract_grid': Contract Grid.\",\n },\n maxPx: {\n type: \"string\",\n description: \"Upper price boundary of the grid range.\",\n },\n minPx: {\n type: \"string\",\n description: \"Lower price boundary of the grid range.\",\n },\n gridNum: {\n type: \"string\",\n description: \"Number of grid levels (integer as string, e.g. '10').\",\n },\n runType: {\n type: \"string\",\n enum: [\"1\", \"2\"],\n description:\n \"Grid spacing type. '1': arithmetic (equal price intervals, default). '2': geometric (equal ratio intervals).\",\n },\n quoteSz: {\n type: \"string\",\n description:\n \"Investment amount in quote currency (e.g. USDT). For spot grid only. Provide quoteSz or baseSz, not both.\",\n },\n baseSz: {\n type: \"string\",\n description:\n \"Investment amount in base currency (e.g. BTC). For spot grid only. Provide quoteSz or baseSz, not both.\",\n },\n direction: {\n type: \"string\",\n enum: [\"long\", \"short\", \"neutral\"],\n description:\n \"Position direction for contract grid. Required for contract_grid.\",\n },\n lever: {\n type: \"string\",\n description:\n \"Leverage multiplier for contract grid (e.g. '5'). Required for contract_grid.\",\n },\n sz: {\n type: \"string\",\n description:\n \"Number of contracts to invest for contract grid. Required for contract_grid.\",\n },\n },\n required: [\"instId\", \"algoOrdType\", \"maxPx\", \"minPx\", \"gridNum\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.privatePost(\n \"/api/v5/tradingBot/grid/order-algo\",\n compactObject({\n instId: requireString(args, \"instId\"),\n algoOrdType: requireString(args, \"algoOrdType\"),\n maxPx: requireString(args, \"maxPx\"),\n minPx: requireString(args, \"minPx\"),\n gridNum: requireString(args, \"gridNum\"),\n runType: readString(args, \"runType\"),\n quoteSz: readString(args, \"quoteSz\"),\n baseSz: readString(args, \"baseSz\"),\n direction: readString(args, \"direction\"),\n lever: readString(args, \"lever\"),\n sz: readString(args, \"sz\"),\n }),\n privateRateLimit(\"grid_create_order\", 20),\n );\n return normalize(response);\n },\n },\n {\n name: \"grid_stop_order\",\n module: \"bot\",\n description:\n \"Stop a running grid trading bot. [CAUTION] This will close or cancel the bot's orders. \" +\n \"For contract grids, stopType controls whether open positions are closed ('1') or only orders are cancelled ('2'). \" +\n \"Private endpoint. Rate limit: 20 req/2s per UID.\",\n isWrite: true,\n inputSchema: {\n type: \"object\",\n properties: {\n algoId: {\n type: \"string\",\n description: \"Bot algo ID to stop.\",\n },\n algoOrdType: {\n type: \"string\",\n enum: [\"grid\", \"contract_grid\", \"moon_grid\"],\n description: \"Grid type of the bot.\",\n },\n instId: {\n type: \"string\",\n description: \"Instrument ID, e.g. 'BTC-USDT'.\",\n },\n stopType: {\n type: \"string\",\n enum: [\"1\", \"2\", \"3\", \"5\", \"6\"],\n description:\n \"Stop behavior. '1': stop and sell/close position (spot: sell quote; contract: market close all). \" +\n \"'2': stop but keep position/assets (default). '3': stop and close at limit price. \" +\n \"'5': stop and partially close. '6': stop without selling spot (smart arbitrage).\",\n },\n },\n required: [\"algoId\", \"algoOrdType\", \"instId\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.privatePost(\n \"/api/v5/tradingBot/grid/stop-order-algo\",\n [compactObject({\n algoId: requireString(args, \"algoId\"),\n algoOrdType: requireString(args, \"algoOrdType\"),\n instId: requireString(args, \"instId\"),\n stopType: readString(args, \"stopType\"),\n })],\n privateRateLimit(\"grid_stop_order\", 20),\n );\n return normalize(response);\n },\n },\n ];\n}\n","import type { ToolSpec } from \"../types.js\";\nimport { registerGridTools } from \"./grid.js\";\n\nexport function registerBotTools(): ToolSpec[] {\n return [...registerGridTools()];\n}\n","import type { ToolSpec } from \"./types.js\";\nimport {\n asRecord,\n assertEnum,\n compactObject,\n readBoolean,\n readNumber,\n readString,\n requireString,\n} from \"./helpers.js\";\nimport { privateRateLimit } from \"./common.js\";\n\nconst FUTURES_INST_TYPES = [\"FUTURES\", \"SWAP\"] as const;\n\nfunction normalize(response: {\n endpoint: string;\n requestTime: string;\n data: unknown;\n}): Record<string, unknown> {\n return {\n endpoint: response.endpoint,\n requestTime: response.requestTime,\n data: response.data,\n };\n}\n\nexport function registerFuturesTools(): ToolSpec[] {\n return [\n {\n name: \"futures_place_order\",\n module: \"futures\",\n description:\n \"Place a FUTURES delivery contract order (e.g. instId: BTC-USDT-240329). Optionally attach TP/SL via tpTriggerPx/slTriggerPx. [CAUTION] Executes real trades. Private endpoint. Rate limit: 60 req/s.\",\n isWrite: true,\n inputSchema: {\n type: \"object\",\n properties: {\n instId: {\n type: \"string\",\n description:\n \"Instrument ID, e.g. BTC-USDT-240329 for quarterly delivery futures.\",\n },\n tdMode: {\n type: \"string\",\n enum: [\"cross\", \"isolated\"],\n description: \"Trade mode: cross or isolated margin.\",\n },\n side: {\n type: \"string\",\n enum: [\"buy\", \"sell\"],\n description:\n \"Order side. In one-way mode: buy=open/add long, sell=open/add short. To close: sell with reduceOnly=true (long) or buy with reduceOnly=true (short). In hedge mode: buy+long=open long, sell+long=close long, sell+short=open short, buy+short=close short.\",\n },\n posSide: {\n type: \"string\",\n enum: [\"long\", \"short\", \"net\"],\n description:\n \"Position side. IMPORTANT: Most OKX accounts use one-way mode — use 'net' in that case. Only use 'long' or 'short' if your account is configured for hedge mode (双向持仓). If you get an error like 'posSide is not valid', switch to 'net'.\",\n },\n ordType: {\n type: \"string\",\n enum: [\"market\", \"limit\", \"post_only\", \"fok\", \"ioc\"],\n description:\n \"Order type. 'market': execute immediately at market price, no px needed. 'limit': execute at px or better, px required. 'post_only': maker-only limit order, px required. 'fok': fill entire order immediately or cancel, px required. 'ioc': fill as much as possible immediately, cancel rest, px required.\",\n },\n sz: {\n type: \"string\",\n description:\n \"Quantity in number of contracts (e.g. '1' = 1 contract).\",\n },\n px: {\n type: \"string\",\n description:\n \"Order price. Required for limit, post_only, fok, ioc orders. Omit for market orders.\",\n },\n reduceOnly: {\n type: \"boolean\",\n description:\n \"Set true to close/reduce an existing position without opening a new one. Use this in one-way mode to close positions instead of posSide.\",\n },\n clOrdId: {\n type: \"string\",\n description: \"Client-supplied order ID. Up to 32 characters.\",\n },\n tag: {\n type: \"string\",\n description: \"Order tag.\",\n },\n tpTriggerPx: {\n type: \"string\",\n description:\n \"Take-profit trigger price. When triggered, places a TP order at tpOrdPx. Assembled into attachAlgoOrds automatically.\",\n },\n tpOrdPx: {\n type: \"string\",\n description:\n \"Take-profit order price. Use '-1' for market order. Required when tpTriggerPx is set.\",\n },\n slTriggerPx: {\n type: \"string\",\n description:\n \"Stop-loss trigger price. When triggered, places a SL order at slOrdPx. Assembled into attachAlgoOrds automatically.\",\n },\n slOrdPx: {\n type: \"string\",\n description:\n \"Stop-loss order price. Use '-1' for market order. Required when slTriggerPx is set.\",\n },\n },\n required: [\"instId\", \"tdMode\", \"side\", \"ordType\", \"sz\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const reduceOnly = args.reduceOnly;\n const tpTriggerPx = readString(args, \"tpTriggerPx\");\n const tpOrdPx = readString(args, \"tpOrdPx\");\n const slTriggerPx = readString(args, \"slTriggerPx\");\n const slOrdPx = readString(args, \"slOrdPx\");\n const algoEntry = compactObject({ tpTriggerPx, tpOrdPx, slTriggerPx, slOrdPx });\n const attachAlgoOrds = Object.keys(algoEntry).length > 0 ? [algoEntry] : undefined;\n const response = await context.client.privatePost(\n \"/api/v5/trade/order\",\n compactObject({\n instId: requireString(args, \"instId\"),\n tdMode: requireString(args, \"tdMode\"),\n side: requireString(args, \"side\"),\n posSide: readString(args, \"posSide\"),\n ordType: requireString(args, \"ordType\"),\n sz: requireString(args, \"sz\"),\n px: readString(args, \"px\"),\n reduceOnly: typeof reduceOnly === \"boolean\" ? String(reduceOnly) : undefined,\n clOrdId: readString(args, \"clOrdId\"),\n tag: readString(args, \"tag\"),\n attachAlgoOrds,\n }),\n privateRateLimit(\"futures_place_order\", 60),\n );\n return normalize(response);\n },\n },\n {\n name: \"futures_cancel_order\",\n module: \"futures\",\n description:\n \"Cancel an unfilled FUTURES delivery order. Private endpoint. Rate limit: 60 req/s.\",\n isWrite: true,\n inputSchema: {\n type: \"object\",\n properties: {\n instId: {\n type: \"string\",\n description: \"Instrument ID, e.g. BTC-USDT-240329.\",\n },\n ordId: {\n type: \"string\",\n description: \"Order ID.\",\n },\n clOrdId: {\n type: \"string\",\n description: \"Client-supplied order ID.\",\n },\n },\n required: [\"instId\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.privatePost(\n \"/api/v5/trade/cancel-order\",\n compactObject({\n instId: requireString(args, \"instId\"),\n ordId: readString(args, \"ordId\"),\n clOrdId: readString(args, \"clOrdId\"),\n }),\n privateRateLimit(\"futures_cancel_order\", 60),\n );\n return normalize(response);\n },\n },\n {\n name: \"futures_get_order\",\n module: \"futures\",\n description:\n \"Get details of a single FUTURES delivery order by ordId or clOrdId. Private endpoint. Rate limit: 60 req/s.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n instId: {\n type: \"string\",\n description: \"Instrument ID, e.g. BTC-USDT-240329.\",\n },\n ordId: {\n type: \"string\",\n description: \"Order ID. Provide either ordId or clOrdId.\",\n },\n clOrdId: {\n type: \"string\",\n description: \"Client-supplied order ID. Provide either ordId or clOrdId.\",\n },\n },\n required: [\"instId\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.privateGet(\n \"/api/v5/trade/order\",\n compactObject({\n instId: requireString(args, \"instId\"),\n ordId: readString(args, \"ordId\"),\n clOrdId: readString(args, \"clOrdId\"),\n }),\n privateRateLimit(\"futures_get_order\", 60),\n );\n return normalize(response);\n },\n },\n {\n name: \"futures_get_orders\",\n module: \"futures\",\n description:\n \"Query FUTURES open orders, history (last 7 days), or archive (up to 3 months). Private. Rate limit: 20 req/s.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n status: {\n type: \"string\",\n enum: [\"open\", \"history\", \"archive\"],\n description:\n \"Query open orders (default), history of last 7 days, or archive of up to 3 months.\",\n },\n instType: {\n type: \"string\",\n enum: [...FUTURES_INST_TYPES],\n description: \"Instrument type: FUTURES (default) or SWAP.\",\n },\n instId: {\n type: \"string\",\n description: \"Instrument ID filter, e.g. BTC-USDT-240329.\",\n },\n ordType: {\n type: \"string\",\n description: \"Order type filter.\",\n },\n state: {\n type: \"string\",\n description: \"Order state filter (for history): canceled, filled.\",\n },\n after: {\n type: \"string\",\n description: \"Pagination cursor: orders earlier than this order ID.\",\n },\n before: {\n type: \"string\",\n description: \"Pagination cursor: orders newer than this order ID.\",\n },\n begin: {\n type: \"string\",\n description: \"Start time filter in milliseconds.\",\n },\n end: {\n type: \"string\",\n description: \"End time filter in milliseconds.\",\n },\n limit: {\n type: \"number\",\n description: \"Number of results, default 100, max 100.\",\n },\n },\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const status = readString(args, \"status\") ?? \"open\";\n const instType = readString(args, \"instType\") ?? \"FUTURES\";\n assertEnum(instType, \"instType\", FUTURES_INST_TYPES);\n const path =\n status === \"archive\"\n ? \"/api/v5/trade/orders-history-archive\"\n : status === \"history\"\n ? \"/api/v5/trade/orders-history\"\n : \"/api/v5/trade/orders-pending\";\n const response = await context.client.privateGet(\n path,\n compactObject({\n instType,\n instId: readString(args, \"instId\"),\n ordType: readString(args, \"ordType\"),\n state: readString(args, \"state\"),\n after: readString(args, \"after\"),\n before: readString(args, \"before\"),\n begin: readString(args, \"begin\"),\n end: readString(args, \"end\"),\n limit: readNumber(args, \"limit\"),\n }),\n privateRateLimit(\"futures_get_orders\", 20),\n );\n return normalize(response);\n },\n },\n {\n name: \"futures_get_positions\",\n module: \"futures\",\n description:\n \"Get current FUTURES delivery contract positions. Private endpoint. Rate limit: 10 req/s.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n instType: {\n type: \"string\",\n enum: [...FUTURES_INST_TYPES],\n description: \"Instrument type: FUTURES (default) or SWAP.\",\n },\n instId: {\n type: \"string\",\n description: \"Instrument ID filter, e.g. BTC-USDT-240329.\",\n },\n posId: {\n type: \"string\",\n description: \"Position ID filter.\",\n },\n },\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const instType = readString(args, \"instType\") ?? \"FUTURES\";\n assertEnum(instType, \"instType\", FUTURES_INST_TYPES);\n const response = await context.client.privateGet(\n \"/api/v5/account/positions\",\n compactObject({\n instType,\n instId: readString(args, \"instId\"),\n posId: readString(args, \"posId\"),\n }),\n privateRateLimit(\"futures_get_positions\", 10),\n );\n return normalize(response);\n },\n },\n {\n name: \"futures_get_fills\",\n module: \"futures\",\n description:\n \"Get FUTURES fill details. archive=false: last 3 days. archive=true: up to 3 months. Private. Rate limit: 20 req/s.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n archive: {\n type: \"boolean\",\n description: \"Set true to query fills history up to 3 months. Default false (last 3 days).\",\n },\n instType: {\n type: \"string\",\n enum: [...FUTURES_INST_TYPES],\n description: \"Instrument type: FUTURES (default) or SWAP.\",\n },\n instId: {\n type: \"string\",\n description: \"Instrument ID filter, e.g. BTC-USDT-240329.\",\n },\n ordId: {\n type: \"string\",\n description: \"Order ID filter.\",\n },\n after: {\n type: \"string\",\n description: \"Pagination cursor: fills earlier than this bill ID.\",\n },\n before: {\n type: \"string\",\n description: \"Pagination cursor: fills newer than this bill ID.\",\n },\n begin: {\n type: \"string\",\n description: \"Start time filter in milliseconds.\",\n },\n end: {\n type: \"string\",\n description: \"End time filter in milliseconds.\",\n },\n limit: {\n type: \"number\",\n description: \"Number of results, max 100. Defaults to 100 (recent) or 20 (archive).\",\n },\n },\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const archive = readBoolean(args, \"archive\") ?? false;\n const instType = readString(args, \"instType\") ?? \"FUTURES\";\n assertEnum(instType, \"instType\", FUTURES_INST_TYPES);\n const path = archive ? \"/api/v5/trade/fills-history\" : \"/api/v5/trade/fills\";\n const response = await context.client.privateGet(\n path,\n compactObject({\n instType,\n instId: readString(args, \"instId\"),\n ordId: readString(args, \"ordId\"),\n after: readString(args, \"after\"),\n before: readString(args, \"before\"),\n begin: readString(args, \"begin\"),\n end: readString(args, \"end\"),\n limit: readNumber(args, \"limit\") ?? (archive ? 20 : undefined),\n }),\n privateRateLimit(\"futures_get_fills\", 20),\n );\n return normalize(response);\n },\n },\n ];\n}\n","import type { ToolSpec } from \"./types.js\";\nimport { asRecord, compactObject, readBoolean, readNumber, readString, requireString } from \"./helpers.js\";\nimport { publicRateLimit, OKX_CANDLE_BARS, OKX_INST_TYPES } from \"./common.js\";\n\nfunction normalize(response: {\n endpoint: string;\n requestTime: string;\n data: unknown;\n}): Record<string, unknown> {\n return {\n endpoint: response.endpoint,\n requestTime: response.requestTime,\n data: response.data,\n };\n}\n\nexport function registerMarketTools(): ToolSpec[] {\n return [\n {\n name: \"market_get_ticker\",\n module: \"market\",\n description:\n \"Get ticker data for a single instrument. Public endpoint, no authentication required. Rate limit: 20 req/s.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n instId: {\n type: \"string\",\n description: \"Instrument ID, e.g. BTC-USDT, BTC-USDT-SWAP.\",\n },\n },\n required: [\"instId\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.publicGet(\n \"/api/v5/market/ticker\",\n { instId: requireString(args, \"instId\") },\n publicRateLimit(\"market_get_ticker\", 20),\n );\n return normalize(response);\n },\n },\n {\n name: \"market_get_tickers\",\n module: \"market\",\n description:\n \"Get ticker data for all instruments of a given type. Public endpoint, no authentication required. Rate limit: 20 req/s.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n instType: {\n type: \"string\",\n enum: [...OKX_INST_TYPES],\n description: \"Instrument type: SPOT, SWAP, FUTURES, OPTION, MARGIN.\",\n },\n uly: {\n type: \"string\",\n description: \"Underlying, e.g. BTC-USD. Required for OPTION.\",\n },\n instFamily: {\n type: \"string\",\n description: \"Instrument family, e.g. BTC-USD.\",\n },\n },\n required: [\"instType\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.publicGet(\n \"/api/v5/market/tickers\",\n compactObject({\n instType: requireString(args, \"instType\"),\n uly: readString(args, \"uly\"),\n instFamily: readString(args, \"instFamily\"),\n }),\n publicRateLimit(\"market_get_tickers\", 20),\n );\n return normalize(response);\n },\n },\n {\n name: \"market_get_orderbook\",\n module: \"market\",\n description:\n \"Get the order book (bids/asks) for an instrument. Public endpoint, no authentication required. Rate limit: 20 req/s.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n instId: {\n type: \"string\",\n description: \"Instrument ID, e.g. BTC-USDT.\",\n },\n sz: {\n type: \"number\",\n description: \"Order book depth per side. Default 1, max 400.\",\n },\n },\n required: [\"instId\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.publicGet(\n \"/api/v5/market/books\",\n compactObject({\n instId: requireString(args, \"instId\"),\n sz: readNumber(args, \"sz\"),\n }),\n publicRateLimit(\"market_get_orderbook\", 20),\n );\n return normalize(response);\n },\n },\n {\n name: \"market_get_candles\",\n module: \"market\",\n description:\n \"Get candlestick (OHLCV) data for an instrument. \" +\n \"history=false (default): recent candles up to 1440 bars. \" +\n \"history=true: older historical data beyond the recent window. \" +\n \"Public endpoint, no authentication required. Rate limit: 40 req/s.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n instId: {\n type: \"string\",\n description: \"Instrument ID, e.g. BTC-USDT.\",\n },\n bar: {\n type: \"string\",\n enum: [...OKX_CANDLE_BARS],\n description: \"Bar size. Default 1m.\",\n },\n after: {\n type: \"string\",\n description: \"Pagination: return records earlier than this timestamp (ms).\",\n },\n before: {\n type: \"string\",\n description: \"Pagination: return records newer than this timestamp (ms).\",\n },\n limit: {\n type: \"number\",\n description: \"Number of results, default 100, max 100.\",\n },\n history: {\n type: \"boolean\",\n description: \"Set true to query historical candles older than the recent window.\",\n },\n },\n required: [\"instId\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const isHistory = readBoolean(args, \"history\") ?? false;\n const path = isHistory\n ? \"/api/v5/market/history-candles\"\n : \"/api/v5/market/candles\";\n const response = await context.client.publicGet(\n path,\n compactObject({\n instId: requireString(args, \"instId\"),\n bar: readString(args, \"bar\"),\n after: readString(args, \"after\"),\n before: readString(args, \"before\"),\n limit: readNumber(args, \"limit\"),\n }),\n publicRateLimit(\"market_get_candles\", 40),\n );\n return normalize(response);\n },\n },\n {\n name: \"market_get_instruments\",\n module: \"market\",\n description:\n \"Get tradable instruments for a given type. Returns contract specs: min order size, lot size, tick size, contract value, settlement currency, listing/expiry time. Essential before placing orders. Public endpoint. Rate limit: 20 req/s.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n instType: {\n type: \"string\",\n enum: [...OKX_INST_TYPES],\n description: \"Instrument type: SPOT, SWAP, FUTURES, OPTION, MARGIN.\",\n },\n instId: {\n type: \"string\",\n description: \"Filter by specific instrument ID, e.g. BTC-USDT-SWAP.\",\n },\n uly: {\n type: \"string\",\n description: \"Underlying filter, e.g. BTC-USD. Required for OPTION.\",\n },\n instFamily: {\n type: \"string\",\n description: \"Instrument family filter, e.g. BTC-USD.\",\n },\n },\n required: [\"instType\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.publicGet(\n \"/api/v5/public/instruments\",\n compactObject({\n instType: requireString(args, \"instType\"),\n instId: readString(args, \"instId\"),\n uly: readString(args, \"uly\"),\n instFamily: readString(args, \"instFamily\"),\n }),\n publicRateLimit(\"market_get_instruments\", 20),\n );\n return normalize(response);\n },\n },\n {\n name: \"market_get_funding_rate\",\n module: \"market\",\n description:\n \"Get funding rate for a SWAP instrument. \" +\n \"history=false (default): current rate and estimated next rate + settlement time. \" +\n \"history=true: historical rates, default 20 records, max 100. \" +\n \"Public endpoint. Rate limit: 20 req/s.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n instId: {\n type: \"string\",\n description: \"SWAP instrument ID, e.g. BTC-USDT-SWAP.\",\n },\n history: {\n type: \"boolean\",\n description: \"Set true to fetch historical funding rates.\",\n },\n after: {\n type: \"string\",\n description: \"Pagination (history only): records earlier than this timestamp (ms).\",\n },\n before: {\n type: \"string\",\n description: \"Pagination (history only): records newer than this timestamp (ms).\",\n },\n limit: {\n type: \"number\",\n description: \"Number of records (history only). Default 20, max 100.\",\n },\n },\n required: [\"instId\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const isHistory = readBoolean(args, \"history\") ?? false;\n if (isHistory) {\n const response = await context.client.publicGet(\n \"/api/v5/public/funding-rate-history\",\n compactObject({\n instId: requireString(args, \"instId\"),\n after: readString(args, \"after\"),\n before: readString(args, \"before\"),\n limit: readNumber(args, \"limit\") ?? 20,\n }),\n publicRateLimit(\"market_get_funding_rate\", 20),\n );\n return normalize(response);\n }\n const response = await context.client.publicGet(\n \"/api/v5/public/funding-rate\",\n { instId: requireString(args, \"instId\") },\n publicRateLimit(\"market_get_funding_rate\", 20),\n );\n return normalize(response);\n },\n },\n {\n name: \"market_get_mark_price\",\n module: \"market\",\n description:\n \"Get mark price for SWAP, FUTURES, or MARGIN instruments. \" +\n \"Mark price is used for liquidation calculations and unrealized PnL. \" +\n \"Public endpoint. Rate limit: 10 req/s.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n instType: {\n type: \"string\",\n enum: [\"MARGIN\", \"SWAP\", \"FUTURES\", \"OPTION\"],\n description: \"Instrument type.\",\n },\n instId: {\n type: \"string\",\n description: \"Filter by specific instrument ID, e.g. BTC-USDT-SWAP.\",\n },\n uly: {\n type: \"string\",\n description: \"Underlying filter, e.g. BTC-USD.\",\n },\n instFamily: {\n type: \"string\",\n description: \"Instrument family filter.\",\n },\n },\n required: [\"instType\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.publicGet(\n \"/api/v5/public/mark-price\",\n compactObject({\n instType: requireString(args, \"instType\"),\n instId: readString(args, \"instId\"),\n uly: readString(args, \"uly\"),\n instFamily: readString(args, \"instFamily\"),\n }),\n publicRateLimit(\"market_get_mark_price\", 10),\n );\n return normalize(response);\n },\n },\n {\n name: \"market_get_trades\",\n module: \"market\",\n description:\n \"Get recent trades for an instrument. Default 20 records, max 500. \" +\n \"Public endpoint, no authentication required. Rate limit: 20 req/s.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n instId: {\n type: \"string\",\n description: \"Instrument ID, e.g. BTC-USDT.\",\n },\n limit: {\n type: \"number\",\n description: \"Number of results. Default 20, max 500.\",\n },\n },\n required: [\"instId\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.publicGet(\n \"/api/v5/market/trades\",\n compactObject({\n instId: requireString(args, \"instId\"),\n limit: readNumber(args, \"limit\") ?? 20,\n }),\n publicRateLimit(\"market_get_trades\", 20),\n );\n return normalize(response);\n },\n },\n {\n name: \"market_get_index_ticker\",\n module: \"market\",\n description:\n \"Get index ticker data (e.g. BTC-USD, ETH-USD index prices). \" +\n \"Index prices are used for mark price calculation and are independent of any single exchange. \" +\n \"Public endpoint. Rate limit: 20 req/s.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n instId: {\n type: \"string\",\n description: \"Index instrument ID, e.g. BTC-USD, ETH-USDT. Omit to return all indices.\",\n },\n quoteCcy: {\n type: \"string\",\n description: \"Quote currency filter, e.g. USD or USDT.\",\n },\n },\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.publicGet(\n \"/api/v5/market/index-tickers\",\n compactObject({\n instId: readString(args, \"instId\"),\n quoteCcy: readString(args, \"quoteCcy\"),\n }),\n publicRateLimit(\"market_get_index_ticker\", 20),\n );\n return normalize(response);\n },\n },\n {\n name: \"market_get_index_candles\",\n module: \"market\",\n description:\n \"Get candlestick data for an index (e.g. BTC-USD index). \" +\n \"history=false (default): recent candles up to 1440 bars. \" +\n \"history=true: older historical data beyond the recent window. \" +\n \"Public endpoint. Rate limit: 20 req/s.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n instId: {\n type: \"string\",\n description: \"Index instrument ID, e.g. BTC-USD.\",\n },\n bar: {\n type: \"string\",\n enum: [...OKX_CANDLE_BARS],\n description: \"Bar size. Default 1m.\",\n },\n after: {\n type: \"string\",\n description: \"Pagination: records earlier than this timestamp (ms).\",\n },\n before: {\n type: \"string\",\n description: \"Pagination: records newer than this timestamp (ms).\",\n },\n limit: {\n type: \"number\",\n description: \"Number of results. Default 100, max 100.\",\n },\n history: {\n type: \"boolean\",\n description: \"Set true to query historical index candles older than the recent window.\",\n },\n },\n required: [\"instId\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const isHistory = readBoolean(args, \"history\") ?? false;\n const path = isHistory\n ? \"/api/v5/market/history-index-candles\"\n : \"/api/v5/market/index-candles\";\n const response = await context.client.publicGet(\n path,\n compactObject({\n instId: requireString(args, \"instId\"),\n bar: readString(args, \"bar\"),\n after: readString(args, \"after\"),\n before: readString(args, \"before\"),\n limit: readNumber(args, \"limit\"),\n }),\n publicRateLimit(\"market_get_index_candles\", 20),\n );\n return normalize(response);\n },\n },\n {\n name: \"market_get_price_limit\",\n module: \"market\",\n description:\n \"Get the current price limit (upper and lower bands) for a SWAP or FUTURES instrument. \" +\n \"Orders placed outside these limits will be rejected by OKX. \" +\n \"Public endpoint. Rate limit: 20 req/s.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n instId: {\n type: \"string\",\n description: \"SWAP or FUTURES instrument ID, e.g. BTC-USDT-SWAP.\",\n },\n },\n required: [\"instId\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.publicGet(\n \"/api/v5/public/price-limit\",\n { instId: requireString(args, \"instId\") },\n publicRateLimit(\"market_get_price_limit\", 20),\n );\n return normalize(response);\n },\n },\n {\n name: \"market_get_open_interest\",\n module: \"market\",\n description:\n \"Get open interest for SWAP, FUTURES, or OPTION instruments. \" +\n \"Useful for gauging market sentiment and positioning. \" +\n \"Public endpoint. Rate limit: 20 req/s.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n instType: {\n type: \"string\",\n enum: [\"SWAP\", \"FUTURES\", \"OPTION\"],\n description: \"Instrument type.\",\n },\n instId: {\n type: \"string\",\n description: \"Filter by specific instrument ID, e.g. BTC-USDT-SWAP.\",\n },\n uly: {\n type: \"string\",\n description: \"Underlying filter, e.g. BTC-USD.\",\n },\n instFamily: {\n type: \"string\",\n description: \"Instrument family filter.\",\n },\n },\n required: [\"instType\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.publicGet(\n \"/api/v5/public/open-interest\",\n compactObject({\n instType: requireString(args, \"instType\"),\n instId: readString(args, \"instId\"),\n uly: readString(args, \"uly\"),\n instFamily: readString(args, \"instFamily\"),\n }),\n publicRateLimit(\"market_get_open_interest\", 20),\n );\n return normalize(response);\n },\n },\n ];\n}\n","import type { ToolSpec } from \"./types.js\";\nimport {\n asRecord,\n assertEnum,\n compactObject,\n readBoolean,\n readNumber,\n readString,\n requireString,\n} from \"./helpers.js\";\nimport { privateRateLimit } from \"./common.js\";\n\nfunction normalize(response: {\n endpoint: string;\n requestTime: string;\n data: unknown;\n}): Record<string, unknown> {\n return {\n endpoint: response.endpoint,\n requestTime: response.requestTime,\n data: response.data,\n };\n}\n\nexport function registerSpotTradeTools(): ToolSpec[] {\n return [\n {\n name: \"spot_place_order\",\n module: \"spot\",\n description:\n \"Place a spot order. Optionally attach take-profit/stop-loss via tpTriggerPx/slTriggerPx (assembled into attachAlgoOrds automatically). [CAUTION] Executes real trades. Private endpoint. Rate limit: 60 req/s per UID.\",\n isWrite: true,\n inputSchema: {\n type: \"object\",\n properties: {\n instId: {\n type: \"string\",\n description: \"Instrument ID, e.g. BTC-USDT.\",\n },\n tdMode: {\n type: \"string\",\n enum: [\"cash\", \"cross\", \"isolated\"],\n description:\n \"Trade mode. Use 'cash' for regular spot trading. Use 'cross' or 'isolated' only for margin trading.\",\n },\n side: {\n type: \"string\",\n enum: [\"buy\", \"sell\"],\n description: \"Order side: 'buy' to purchase, 'sell' to sell.\",\n },\n ordType: {\n type: \"string\",\n enum: [\"market\", \"limit\", \"post_only\", \"fok\", \"ioc\"],\n description:\n \"Order type. 'market': execute immediately at market price, no px needed. 'limit': execute at px or better, px required. 'post_only': maker-only limit order, px required. 'fok': fill entire order immediately or cancel, px required. 'ioc': fill as much as possible immediately, cancel rest, px required.\",\n },\n sz: {\n type: \"string\",\n description:\n \"Quantity. For market BUY: amount in quote currency (e.g. '100' means spend 100 USDT). For all other order types: amount in base currency (e.g. '0.001' means 0.001 BTC). For limit orders, always use base currency.\",\n },\n px: {\n type: \"string\",\n description:\n \"Order price in quote currency. Required for limit, post_only, fok, ioc orders. Omit for market orders.\",\n },\n clOrdId: {\n type: \"string\",\n description: \"Client-supplied order ID. Up to 32 characters.\",\n },\n tag: {\n type: \"string\",\n description: \"Order tag.\",\n },\n tpTriggerPx: {\n type: \"string\",\n description:\n \"Take-profit trigger price. When triggered, places a TP order at tpOrdPx. Assembled into attachAlgoOrds automatically.\",\n },\n tpOrdPx: {\n type: \"string\",\n description:\n \"Take-profit order price. Use '-1' for market order. Required when tpTriggerPx is set.\",\n },\n slTriggerPx: {\n type: \"string\",\n description:\n \"Stop-loss trigger price. When triggered, places a SL order at slOrdPx. Assembled into attachAlgoOrds automatically.\",\n },\n slOrdPx: {\n type: \"string\",\n description:\n \"Stop-loss order price. Use '-1' for market order. Required when slTriggerPx is set.\",\n },\n },\n required: [\"instId\", \"tdMode\", \"side\", \"ordType\", \"sz\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const tpTriggerPx = readString(args, \"tpTriggerPx\");\n const tpOrdPx = readString(args, \"tpOrdPx\");\n const slTriggerPx = readString(args, \"slTriggerPx\");\n const slOrdPx = readString(args, \"slOrdPx\");\n const algoEntry = compactObject({ tpTriggerPx, tpOrdPx, slTriggerPx, slOrdPx });\n const attachAlgoOrds = Object.keys(algoEntry).length > 0 ? [algoEntry] : undefined;\n const response = await context.client.privatePost(\n \"/api/v5/trade/order\",\n compactObject({\n instId: requireString(args, \"instId\"),\n tdMode: requireString(args, \"tdMode\"),\n side: requireString(args, \"side\"),\n ordType: requireString(args, \"ordType\"),\n sz: requireString(args, \"sz\"),\n px: readString(args, \"px\"),\n clOrdId: readString(args, \"clOrdId\"),\n tag: readString(args, \"tag\"),\n attachAlgoOrds,\n }),\n privateRateLimit(\"spot_place_order\", 60),\n );\n return normalize(response);\n },\n },\n {\n name: \"spot_cancel_order\",\n module: \"spot\",\n description:\n \"Cancel an unfilled spot order by order ID or client order ID. Private endpoint. Rate limit: 60 req/s per UID.\",\n isWrite: true,\n inputSchema: {\n type: \"object\",\n properties: {\n instId: {\n type: \"string\",\n description: \"Instrument ID, e.g. BTC-USDT.\",\n },\n ordId: {\n type: \"string\",\n description: \"Order ID.\",\n },\n clOrdId: {\n type: \"string\",\n description: \"Client-supplied order ID.\",\n },\n },\n required: [\"instId\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.privatePost(\n \"/api/v5/trade/cancel-order\",\n compactObject({\n instId: requireString(args, \"instId\"),\n ordId: readString(args, \"ordId\"),\n clOrdId: readString(args, \"clOrdId\"),\n }),\n privateRateLimit(\"spot_cancel_order\", 60),\n );\n return normalize(response);\n },\n },\n {\n name: \"spot_amend_order\",\n module: \"spot\",\n description:\n \"Amend an unfilled spot order (modify price or size). Private endpoint. Rate limit: 60 req/s per UID.\",\n isWrite: true,\n inputSchema: {\n type: \"object\",\n properties: {\n instId: {\n type: \"string\",\n description: \"Instrument ID, e.g. BTC-USDT.\",\n },\n ordId: {\n type: \"string\",\n description: \"Order ID.\",\n },\n clOrdId: {\n type: \"string\",\n description: \"Client-supplied order ID.\",\n },\n newSz: {\n type: \"string\",\n description: \"New quantity.\",\n },\n newPx: {\n type: \"string\",\n description: \"New price.\",\n },\n newClOrdId: {\n type: \"string\",\n description: \"New client order ID after amendment.\",\n },\n },\n required: [\"instId\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.privatePost(\n \"/api/v5/trade/amend-order\",\n compactObject({\n instId: requireString(args, \"instId\"),\n ordId: readString(args, \"ordId\"),\n clOrdId: readString(args, \"clOrdId\"),\n newSz: readString(args, \"newSz\"),\n newPx: readString(args, \"newPx\"),\n newClOrdId: readString(args, \"newClOrdId\"),\n }),\n privateRateLimit(\"spot_amend_order\", 60),\n );\n return normalize(response);\n },\n },\n {\n name: \"spot_get_orders\",\n module: \"spot\",\n description:\n \"Query spot open orders, order history (last 7 days), or order archive (up to 3 months). Private endpoint. Rate limit: 20 req/s.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n status: {\n type: \"string\",\n enum: [\"open\", \"history\", \"archive\"],\n description:\n \"Query open orders (default), history of last 7 days, or archive of up to 3 months.\",\n },\n instId: {\n type: \"string\",\n description: \"Instrument ID filter, e.g. BTC-USDT.\",\n },\n ordType: {\n type: \"string\",\n description: \"Order type filter.\",\n },\n state: {\n type: \"string\",\n description: \"Order state filter (for history): canceled, filled.\",\n },\n after: {\n type: \"string\",\n description: \"Pagination cursor: orders earlier than this order ID.\",\n },\n before: {\n type: \"string\",\n description: \"Pagination cursor: orders newer than this order ID.\",\n },\n begin: {\n type: \"string\",\n description: \"Start time filter in milliseconds.\",\n },\n end: {\n type: \"string\",\n description: \"End time filter in milliseconds.\",\n },\n limit: {\n type: \"number\",\n description: \"Number of results, default 100, max 100.\",\n },\n },\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const status = readString(args, \"status\") ?? \"open\";\n const path =\n status === \"archive\"\n ? \"/api/v5/trade/orders-history-archive\"\n : status === \"history\"\n ? \"/api/v5/trade/orders-history\"\n : \"/api/v5/trade/orders-pending\";\n const response = await context.client.privateGet(\n path,\n compactObject({\n instType: \"SPOT\",\n instId: readString(args, \"instId\"),\n ordType: readString(args, \"ordType\"),\n state: readString(args, \"state\"),\n after: readString(args, \"after\"),\n before: readString(args, \"before\"),\n begin: readString(args, \"begin\"),\n end: readString(args, \"end\"),\n limit: readNumber(args, \"limit\"),\n }),\n privateRateLimit(\"spot_get_orders\", 20),\n );\n return normalize(response);\n },\n },\n {\n name: \"spot_place_algo_order\",\n module: \"spot\",\n description:\n \"Place a spot algo order with take-profit and/or stop-loss. [CAUTION] Executes real trades. Private endpoint. Rate limit: 20 req/s per UID.\",\n isWrite: true,\n inputSchema: {\n type: \"object\",\n properties: {\n instId: {\n type: \"string\",\n description: \"Instrument ID, e.g. BTC-USDT.\",\n },\n side: {\n type: \"string\",\n enum: [\"buy\", \"sell\"],\n description: \"Order side.\",\n },\n ordType: {\n type: \"string\",\n enum: [\"conditional\", \"oco\"],\n description:\n \"'conditional': single TP or SL. 'oco': both TP and SL in one order (one-cancels-the-other).\",\n },\n sz: {\n type: \"string\",\n description: \"Quantity in base currency, e.g. '0.001' for 0.001 BTC.\",\n },\n tpTriggerPx: {\n type: \"string\",\n description: \"Take-profit trigger price.\",\n },\n tpOrdPx: {\n type: \"string\",\n description: \"Take-profit order price. Use '-1' for market order.\",\n },\n slTriggerPx: {\n type: \"string\",\n description: \"Stop-loss trigger price.\",\n },\n slOrdPx: {\n type: \"string\",\n description: \"Stop-loss order price. Use '-1' for market order.\",\n },\n },\n required: [\"instId\", \"side\", \"ordType\", \"sz\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.privatePost(\n \"/api/v5/trade/order-algo\",\n compactObject({\n instId: requireString(args, \"instId\"),\n tdMode: \"cash\",\n side: requireString(args, \"side\"),\n ordType: requireString(args, \"ordType\"),\n sz: requireString(args, \"sz\"),\n tpTriggerPx: readString(args, \"tpTriggerPx\"),\n tpOrdPx: readString(args, \"tpOrdPx\"),\n slTriggerPx: readString(args, \"slTriggerPx\"),\n slOrdPx: readString(args, \"slOrdPx\"),\n }),\n privateRateLimit(\"spot_place_algo_order\", 20),\n );\n return normalize(response);\n },\n },\n {\n name: \"spot_amend_algo_order\",\n module: \"spot\",\n description:\n \"Amend a pending spot algo order (modify TP/SL prices or size). Private endpoint. Rate limit: 20 req/s.\",\n isWrite: true,\n inputSchema: {\n type: \"object\",\n properties: {\n instId: { type: \"string\", description: \"Instrument ID, e.g. BTC-USDT.\" },\n algoId: { type: \"string\", description: \"Algo order ID to amend.\" },\n newSz: { type: \"string\", description: \"New quantity in base currency.\" },\n newTpTriggerPx: { type: \"string\", description: \"New take-profit trigger price.\" },\n newTpOrdPx: { type: \"string\", description: \"New take-profit order price. Use '-1' for market.\" },\n newSlTriggerPx: { type: \"string\", description: \"New stop-loss trigger price.\" },\n newSlOrdPx: { type: \"string\", description: \"New stop-loss order price. Use '-1' for market.\" },\n },\n required: [\"instId\", \"algoId\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.privatePost(\n \"/api/v5/trade/amend-algos\",\n compactObject({\n instId: requireString(args, \"instId\"),\n algoId: requireString(args, \"algoId\"),\n newSz: readString(args, \"newSz\"),\n newTpTriggerPx: readString(args, \"newTpTriggerPx\"),\n newTpOrdPx: readString(args, \"newTpOrdPx\"),\n newSlTriggerPx: readString(args, \"newSlTriggerPx\"),\n newSlOrdPx: readString(args, \"newSlOrdPx\"),\n }),\n privateRateLimit(\"spot_amend_algo_order\", 20),\n );\n return normalize(response);\n },\n },\n {\n name: \"spot_cancel_algo_order\",\n module: \"spot\",\n description:\n \"Cancel a spot algo order (TP/SL). Private endpoint. Rate limit: 20 req/s per UID.\",\n isWrite: true,\n inputSchema: {\n type: \"object\",\n properties: {\n instId: {\n type: \"string\",\n description: \"Instrument ID, e.g. BTC-USDT.\",\n },\n algoId: {\n type: \"string\",\n description: \"Algo order ID.\",\n },\n },\n required: [\"instId\", \"algoId\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.privatePost(\n \"/api/v5/trade/cancel-algos\",\n [\n {\n instId: requireString(args, \"instId\"),\n algoId: requireString(args, \"algoId\"),\n },\n ],\n privateRateLimit(\"spot_cancel_algo_order\", 20),\n );\n return normalize(response);\n },\n },\n {\n name: \"spot_get_algo_orders\",\n module: \"spot\",\n description:\n \"Query spot algo orders (TP/SL) — pending or history. Private endpoint. Rate limit: 20 req/s.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n status: {\n type: \"string\",\n enum: [\"pending\", \"history\"],\n description: \"Query pending algo orders (default) or history.\",\n },\n instId: {\n type: \"string\",\n description: \"Instrument ID filter, e.g. BTC-USDT.\",\n },\n ordType: {\n type: \"string\",\n enum: [\"conditional\", \"oco\"],\n description: \"Filter by algo order type.\",\n },\n after: {\n type: \"string\",\n description: \"Pagination cursor: orders earlier than this algo ID.\",\n },\n before: {\n type: \"string\",\n description: \"Pagination cursor: orders newer than this algo ID.\",\n },\n limit: {\n type: \"number\",\n description: \"Number of results, default 100, max 100.\",\n },\n },\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const status = readString(args, \"status\") ?? \"pending\";\n const path =\n status === \"history\"\n ? \"/api/v5/trade/orders-algo-history\"\n : \"/api/v5/trade/orders-algo-pending\";\n const ordType = readString(args, \"ordType\");\n const baseParams = compactObject({\n instType: \"SPOT\",\n instId: readString(args, \"instId\"),\n after: readString(args, \"after\"),\n before: readString(args, \"before\"),\n limit: readNumber(args, \"limit\"),\n });\n\n if (ordType) {\n const response = await context.client.privateGet(\n path,\n { ...baseParams, ordType },\n privateRateLimit(\"spot_get_algo_orders\", 20),\n );\n return normalize(response);\n }\n\n // ordType is required by OKX; fetch both spot types in parallel and merge\n const [r1, r2] = await Promise.all([\n context.client.privateGet(path, { ...baseParams, ordType: \"conditional\" }, privateRateLimit(\"spot_get_algo_orders\", 20)),\n context.client.privateGet(path, { ...baseParams, ordType: \"oco\" }, privateRateLimit(\"spot_get_algo_orders\", 20)),\n ]);\n const merged = [\n ...((r1.data as unknown[]) ?? []),\n ...((r2.data as unknown[]) ?? []),\n ];\n return { endpoint: r1.endpoint, requestTime: r1.requestTime, data: merged };\n },\n },\n {\n name: \"spot_get_fills\",\n module: \"spot\",\n description:\n \"Get spot transaction fill details. \" +\n \"archive=false (default): last 3 days. \" +\n \"archive=true: up to 3 months, default limit 20. \" +\n \"Private endpoint. Rate limit: 20 req/s.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n archive: {\n type: \"boolean\",\n description: \"Set true to query fills history up to 3 months. Default false (last 3 days).\",\n },\n instId: {\n type: \"string\",\n description: \"Instrument ID filter, e.g. BTC-USDT.\",\n },\n ordId: {\n type: \"string\",\n description: \"Order ID filter.\",\n },\n after: {\n type: \"string\",\n description: \"Pagination cursor: fills earlier than this bill ID.\",\n },\n before: {\n type: \"string\",\n description: \"Pagination cursor: fills newer than this bill ID.\",\n },\n begin: {\n type: \"string\",\n description: \"Start time filter in milliseconds.\",\n },\n end: {\n type: \"string\",\n description: \"End time filter in milliseconds.\",\n },\n limit: {\n type: \"number\",\n description: \"Number of results, max 100. Defaults to 100 (recent) or 20 (archive).\",\n },\n },\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const archive = readBoolean(args, \"archive\") ?? false;\n const path = archive ? \"/api/v5/trade/fills-history\" : \"/api/v5/trade/fills\";\n const response = await context.client.privateGet(\n path,\n compactObject({\n instType: \"SPOT\",\n instId: readString(args, \"instId\"),\n ordId: readString(args, \"ordId\"),\n after: readString(args, \"after\"),\n before: readString(args, \"before\"),\n begin: readString(args, \"begin\"),\n end: readString(args, \"end\"),\n limit: readNumber(args, \"limit\") ?? (archive ? 20 : undefined),\n }),\n privateRateLimit(\"spot_get_fills\", 20),\n );\n return normalize(response);\n },\n },\n {\n name: \"spot_batch_orders\",\n module: \"spot\",\n description:\n \"[CAUTION] Batch place/cancel/amend up to 20 spot orders in one request. Use action='place'/'cancel'/'amend'. Private. Rate limit: 60 req/s.\",\n isWrite: true,\n inputSchema: {\n type: \"object\",\n properties: {\n action: {\n type: \"string\",\n enum: [\"place\", \"cancel\", \"amend\"],\n description:\n \"Operation type. 'place': batch place orders. 'cancel': batch cancel by ordId/clOrdId. 'amend': batch modify newSz/newPx.\",\n },\n orders: {\n type: \"array\",\n description:\n \"Array of order objects (max 20). For 'place': {instId, side, ordType, sz, tdMode?, px?, clOrdId?, tpTriggerPx?, tpOrdPx?, slTriggerPx?, slOrdPx?}. tdMode defaults to 'cash'. For 'cancel': {instId, ordId} or {instId, clOrdId}. For 'amend': {instId, ordId or clOrdId, newSz?, newPx?}.\",\n items: {\n type: \"object\",\n },\n },\n },\n required: [\"action\", \"orders\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const action = requireString(args, \"action\");\n assertEnum(action, \"action\", [\"place\", \"cancel\", \"amend\"]);\n const orders = args.orders;\n if (!Array.isArray(orders) || orders.length === 0) {\n throw new Error(\"orders must be a non-empty array.\");\n }\n const endpointMap: Record<string, string> = {\n place: \"/api/v5/trade/batch-orders\",\n cancel: \"/api/v5/trade/cancel-batch-orders\",\n amend: \"/api/v5/trade/amend-batch-orders\",\n };\n const body: Record<string, unknown>[] =\n action === \"place\"\n ? orders.map((order: unknown) => {\n const o = asRecord(order);\n const tpTriggerPx = readString(o, \"tpTriggerPx\");\n const tpOrdPx = readString(o, \"tpOrdPx\");\n const slTriggerPx = readString(o, \"slTriggerPx\");\n const slOrdPx = readString(o, \"slOrdPx\");\n const algoEntry = compactObject({ tpTriggerPx, tpOrdPx, slTriggerPx, slOrdPx });\n const attachAlgoOrds =\n Object.keys(algoEntry).length > 0 ? [algoEntry] : undefined;\n return compactObject({\n instId: requireString(o, \"instId\"),\n tdMode: readString(o, \"tdMode\") ?? \"cash\",\n side: requireString(o, \"side\"),\n ordType: requireString(o, \"ordType\"),\n sz: requireString(o, \"sz\"),\n px: readString(o, \"px\"),\n clOrdId: readString(o, \"clOrdId\"),\n attachAlgoOrds,\n });\n })\n : (orders as Record<string, unknown>[]);\n const response = await context.client.privatePost(\n endpointMap[action],\n body,\n privateRateLimit(\"spot_batch_orders\", 60),\n );\n return normalize(response);\n },\n },\n {\n name: \"spot_get_order\",\n module: \"spot\",\n description:\n \"Get details of a single spot order by order ID or client order ID. Private endpoint. Rate limit: 60 req/s.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n instId: {\n type: \"string\",\n description: \"Instrument ID, e.g. BTC-USDT.\",\n },\n ordId: {\n type: \"string\",\n description: \"Order ID. Provide either ordId or clOrdId.\",\n },\n clOrdId: {\n type: \"string\",\n description: \"Client-supplied order ID. Provide either ordId or clOrdId.\",\n },\n },\n required: [\"instId\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.privateGet(\n \"/api/v5/trade/order\",\n compactObject({\n instId: requireString(args, \"instId\"),\n ordId: readString(args, \"ordId\"),\n clOrdId: readString(args, \"clOrdId\"),\n }),\n privateRateLimit(\"spot_get_order\", 60),\n );\n return normalize(response);\n },\n },\n {\n name: \"spot_batch_amend\",\n module: \"spot\",\n description:\n \"[CAUTION] Batch amend up to 20 unfilled spot orders in one request. Modify price and/or size per order. Private endpoint. Rate limit: 60 req/s.\",\n isWrite: true,\n inputSchema: {\n type: \"object\",\n properties: {\n orders: {\n type: \"array\",\n description:\n \"Array of orders to amend (max 20). Each item: {instId: string, ordId?: string, clOrdId?: string, newSz?: string, newPx?: string}.\",\n items: { type: \"object\" },\n },\n },\n required: [\"orders\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const orders = args.orders;\n if (!Array.isArray(orders) || orders.length === 0) {\n throw new Error(\"orders must be a non-empty array.\");\n }\n const response = await context.client.privatePost(\n \"/api/v5/trade/amend-batch-orders\",\n orders as Record<string, unknown>[],\n privateRateLimit(\"spot_batch_amend\", 60),\n );\n return normalize(response);\n },\n },\n {\n name: \"spot_batch_cancel\",\n module: \"spot\",\n description:\n \"[CAUTION] Batch cancel up to 20 spot orders in one request. Provide instId plus ordId or clOrdId for each order. Private endpoint. Rate limit: 60 req/s.\",\n isWrite: true,\n inputSchema: {\n type: \"object\",\n properties: {\n orders: {\n type: \"array\",\n description:\n \"Array of orders to cancel (max 20). Each item: {instId: string, ordId?: string, clOrdId?: string}.\",\n items: { type: \"object\" },\n },\n },\n required: [\"orders\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const orders = args.orders;\n if (!Array.isArray(orders) || orders.length === 0) {\n throw new Error(\"orders must be a non-empty array.\");\n }\n const response = await context.client.privatePost(\n \"/api/v5/trade/cancel-batch-orders\",\n orders as Record<string, unknown>[],\n privateRateLimit(\"spot_batch_cancel\", 60),\n );\n return normalize(response);\n },\n },\n ];\n}\n","import type { ToolSpec } from \"./types.js\";\nimport {\n asRecord,\n assertEnum,\n compactObject,\n readBoolean,\n readNumber,\n readString,\n requireString,\n} from \"./helpers.js\";\nimport { privateRateLimit } from \"./common.js\";\n\nconst SWAP_INST_TYPES = [\"SWAP\", \"FUTURES\"] as const;\n\nfunction normalize(response: {\n endpoint: string;\n requestTime: string;\n data: unknown;\n}): Record<string, unknown> {\n return {\n endpoint: response.endpoint,\n requestTime: response.requestTime,\n data: response.data,\n };\n}\n\nexport function registerSwapTradeTools(): ToolSpec[] {\n return [\n {\n name: \"swap_place_order\",\n module: \"swap\",\n description:\n \"Place a SWAP or FUTURES perpetual/delivery contract order. Optionally attach take-profit/stop-loss via tpTriggerPx/slTriggerPx (assembled into attachAlgoOrds automatically). [CAUTION] Executes real trades. Private endpoint. Rate limit: 60 req/s per UID.\",\n isWrite: true,\n inputSchema: {\n type: \"object\",\n properties: {\n instId: {\n type: \"string\",\n description:\n \"Instrument ID, e.g. BTC-USDT-SWAP for perpetual, BTC-USD-240329 for delivery futures.\",\n },\n tdMode: {\n type: \"string\",\n enum: [\"cross\", \"isolated\"],\n description: \"Trade mode: cross or isolated margin.\",\n },\n side: {\n type: \"string\",\n enum: [\"buy\", \"sell\"],\n description:\n \"Order side. In one-way mode: buy=open/add long, sell=open/add short. To close: sell with reduceOnly=true (long) or buy with reduceOnly=true (short). In hedge mode: buy+long=open long, sell+long=close long, sell+short=open short, buy+short=close short.\",\n },\n posSide: {\n type: \"string\",\n enum: [\"long\", \"short\", \"net\"],\n description:\n \"Position side. IMPORTANT: Most OKX accounts use one-way mode — use 'net' in that case. Only use 'long' or 'short' if your account is configured for hedge mode (双向持仓). If you get an error like 'posSide is not valid', switch to 'net'.\",\n },\n ordType: {\n type: \"string\",\n enum: [\"market\", \"limit\", \"post_only\", \"fok\", \"ioc\"],\n description:\n \"Order type. 'market': execute immediately at market price, no px needed. 'limit': execute at px or better, px required. 'post_only': maker-only limit order, px required. 'fok': fill entire order immediately or cancel, px required. 'ioc': fill as much as possible immediately, cancel rest, px required.\",\n },\n sz: {\n type: \"string\",\n description:\n \"Quantity in number of contracts (e.g. '1' = 1 contract). For BTC-USDT-SWAP, 1 contract = 0.01 BTC.\",\n },\n px: {\n type: \"string\",\n description:\n \"Order price. Required for limit, post_only, fok, ioc orders. Omit for market orders.\",\n },\n reduceOnly: {\n type: \"boolean\",\n description:\n \"Set true to close/reduce an existing position without opening a new one. Use this in one-way mode to close positions instead of posSide.\",\n },\n clOrdId: {\n type: \"string\",\n description: \"Client-supplied order ID. Up to 32 characters.\",\n },\n tag: {\n type: \"string\",\n description: \"Order tag.\",\n },\n tpTriggerPx: {\n type: \"string\",\n description:\n \"Take-profit trigger price. When triggered, places a TP order at tpOrdPx. Assembled into attachAlgoOrds automatically.\",\n },\n tpOrdPx: {\n type: \"string\",\n description:\n \"Take-profit order price. Use '-1' for market order. Required when tpTriggerPx is set.\",\n },\n slTriggerPx: {\n type: \"string\",\n description:\n \"Stop-loss trigger price. When triggered, places a SL order at slOrdPx. Assembled into attachAlgoOrds automatically.\",\n },\n slOrdPx: {\n type: \"string\",\n description:\n \"Stop-loss order price. Use '-1' for market order. Required when slTriggerPx is set.\",\n },\n },\n required: [\"instId\", \"tdMode\", \"side\", \"ordType\", \"sz\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const reduceOnly = args.reduceOnly;\n const tpTriggerPx = readString(args, \"tpTriggerPx\");\n const tpOrdPx = readString(args, \"tpOrdPx\");\n const slTriggerPx = readString(args, \"slTriggerPx\");\n const slOrdPx = readString(args, \"slOrdPx\");\n const algoEntry = compactObject({ tpTriggerPx, tpOrdPx, slTriggerPx, slOrdPx });\n const attachAlgoOrds = Object.keys(algoEntry).length > 0 ? [algoEntry] : undefined;\n const response = await context.client.privatePost(\n \"/api/v5/trade/order\",\n compactObject({\n instId: requireString(args, \"instId\"),\n tdMode: requireString(args, \"tdMode\"),\n side: requireString(args, \"side\"),\n posSide: readString(args, \"posSide\"),\n ordType: requireString(args, \"ordType\"),\n sz: requireString(args, \"sz\"),\n px: readString(args, \"px\"),\n reduceOnly: typeof reduceOnly === \"boolean\" ? String(reduceOnly) : undefined,\n clOrdId: readString(args, \"clOrdId\"),\n tag: readString(args, \"tag\"),\n attachAlgoOrds,\n }),\n privateRateLimit(\"swap_place_order\", 60),\n );\n return normalize(response);\n },\n },\n {\n name: \"swap_cancel_order\",\n module: \"swap\",\n description:\n \"Cancel an unfilled SWAP or FUTURES order. Private endpoint. Rate limit: 60 req/s per UID.\",\n isWrite: true,\n inputSchema: {\n type: \"object\",\n properties: {\n instId: {\n type: \"string\",\n description: \"Instrument ID, e.g. BTC-USDT-SWAP.\",\n },\n ordId: {\n type: \"string\",\n description: \"Order ID.\",\n },\n clOrdId: {\n type: \"string\",\n description: \"Client-supplied order ID.\",\n },\n },\n required: [\"instId\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.privatePost(\n \"/api/v5/trade/cancel-order\",\n compactObject({\n instId: requireString(args, \"instId\"),\n ordId: readString(args, \"ordId\"),\n clOrdId: readString(args, \"clOrdId\"),\n }),\n privateRateLimit(\"swap_cancel_order\", 60),\n );\n return normalize(response);\n },\n },\n {\n name: \"swap_get_orders\",\n module: \"swap\",\n description:\n \"Query SWAP or FUTURES open orders, order history (last 7 days), or order archive (up to 3 months). Private endpoint. Rate limit: 20 req/s.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n status: {\n type: \"string\",\n enum: [\"open\", \"history\", \"archive\"],\n description:\n \"Query open orders (default), history of last 7 days, or archive of up to 3 months.\",\n },\n instType: {\n type: \"string\",\n enum: [...SWAP_INST_TYPES],\n description: \"Instrument type: SWAP (default) or FUTURES.\",\n },\n instId: {\n type: \"string\",\n description: \"Instrument ID filter.\",\n },\n ordType: {\n type: \"string\",\n description: \"Order type filter.\",\n },\n state: {\n type: \"string\",\n description: \"Order state filter (for history): canceled, filled.\",\n },\n after: {\n type: \"string\",\n description: \"Pagination cursor: orders earlier than this order ID.\",\n },\n before: {\n type: \"string\",\n description: \"Pagination cursor: orders newer than this order ID.\",\n },\n begin: {\n type: \"string\",\n description: \"Start time filter in milliseconds.\",\n },\n end: {\n type: \"string\",\n description: \"End time filter in milliseconds.\",\n },\n limit: {\n type: \"number\",\n description: \"Number of results, default 100, max 100.\",\n },\n },\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const status = readString(args, \"status\") ?? \"open\";\n const instType = readString(args, \"instType\") ?? \"SWAP\";\n assertEnum(instType, \"instType\", SWAP_INST_TYPES);\n const path =\n status === \"archive\"\n ? \"/api/v5/trade/orders-history-archive\"\n : status === \"history\"\n ? \"/api/v5/trade/orders-history\"\n : \"/api/v5/trade/orders-pending\";\n const response = await context.client.privateGet(\n path,\n compactObject({\n instType,\n instId: readString(args, \"instId\"),\n ordType: readString(args, \"ordType\"),\n state: readString(args, \"state\"),\n after: readString(args, \"after\"),\n before: readString(args, \"before\"),\n begin: readString(args, \"begin\"),\n end: readString(args, \"end\"),\n limit: readNumber(args, \"limit\"),\n }),\n privateRateLimit(\"swap_get_orders\", 20),\n );\n return normalize(response);\n },\n },\n {\n name: \"swap_get_positions\",\n module: \"swap\",\n description:\n \"Get current SWAP or FUTURES positions. Private endpoint. Rate limit: 10 req/s.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n instType: {\n type: \"string\",\n enum: [...SWAP_INST_TYPES],\n description: \"Instrument type: SWAP (default) or FUTURES.\",\n },\n instId: {\n type: \"string\",\n description: \"Instrument ID filter, e.g. BTC-USDT-SWAP.\",\n },\n posId: {\n type: \"string\",\n description: \"Position ID filter.\",\n },\n },\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const instType = readString(args, \"instType\") ?? \"SWAP\";\n assertEnum(instType, \"instType\", SWAP_INST_TYPES);\n const response = await context.client.privateGet(\n \"/api/v5/account/positions\",\n compactObject({\n instType,\n instId: readString(args, \"instId\"),\n posId: readString(args, \"posId\"),\n }),\n privateRateLimit(\"swap_get_positions\", 10),\n );\n return normalize(response);\n },\n },\n {\n name: \"swap_set_leverage\",\n module: \"swap\",\n description:\n \"Set leverage for a SWAP or FUTURES instrument or position. [CAUTION] Changes risk parameters. Private endpoint. Rate limit: 20 req/s.\",\n isWrite: true,\n inputSchema: {\n type: \"object\",\n properties: {\n instId: {\n type: \"string\",\n description: \"Instrument ID, e.g. BTC-USDT-SWAP.\",\n },\n lever: {\n type: \"string\",\n description: \"Leverage value, e.g. '10'.\",\n },\n mgnMode: {\n type: \"string\",\n enum: [\"cross\", \"isolated\"],\n description: \"Margin mode.\",\n },\n posSide: {\n type: \"string\",\n enum: [\"long\", \"short\", \"net\"],\n description:\n \"Position side. Required for isolated margin in hedge mode.\",\n },\n },\n required: [\"instId\", \"lever\", \"mgnMode\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.privatePost(\n \"/api/v5/account/set-leverage\",\n compactObject({\n instId: requireString(args, \"instId\"),\n lever: requireString(args, \"lever\"),\n mgnMode: requireString(args, \"mgnMode\"),\n posSide: readString(args, \"posSide\"),\n }),\n privateRateLimit(\"swap_set_leverage\", 20),\n );\n return normalize(response);\n },\n },\n {\n name: \"swap_amend_algo_order\",\n module: \"swap\",\n description:\n \"Amend a pending SWAP/FUTURES algo order (modify TP/SL prices or size). Private endpoint. Rate limit: 20 req/s.\",\n isWrite: true,\n inputSchema: {\n type: \"object\",\n properties: {\n instId: { type: \"string\", description: \"Instrument ID, e.g. BTC-USDT-SWAP.\" },\n algoId: { type: \"string\", description: \"Algo order ID to amend.\" },\n newSz: { type: \"string\", description: \"New quantity in number of contracts.\" },\n newTpTriggerPx: { type: \"string\", description: \"New take-profit trigger price.\" },\n newTpOrdPx: { type: \"string\", description: \"New take-profit order price. Use '-1' for market.\" },\n newSlTriggerPx: { type: \"string\", description: \"New stop-loss trigger price.\" },\n newSlOrdPx: { type: \"string\", description: \"New stop-loss order price. Use '-1' for market.\" },\n },\n required: [\"instId\", \"algoId\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.privatePost(\n \"/api/v5/trade/amend-algos\",\n compactObject({\n instId: requireString(args, \"instId\"),\n algoId: requireString(args, \"algoId\"),\n newSz: readString(args, \"newSz\"),\n newTpTriggerPx: readString(args, \"newTpTriggerPx\"),\n newTpOrdPx: readString(args, \"newTpOrdPx\"),\n newSlTriggerPx: readString(args, \"newSlTriggerPx\"),\n newSlOrdPx: readString(args, \"newSlOrdPx\"),\n }),\n privateRateLimit(\"swap_amend_algo_order\", 20),\n );\n return normalize(response);\n },\n },\n {\n name: \"swap_get_fills\",\n module: \"swap\",\n description:\n \"Get SWAP or FUTURES transaction fill details. \" +\n \"archive=false (default): last 3 days. \" +\n \"archive=true: up to 3 months, default limit 20. \" +\n \"Private endpoint. Rate limit: 20 req/s.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n archive: {\n type: \"boolean\",\n description: \"Set true to query fills history up to 3 months. Default false (last 3 days).\",\n },\n instType: {\n type: \"string\",\n enum: [...SWAP_INST_TYPES],\n description: \"Instrument type: SWAP (default) or FUTURES.\",\n },\n instId: {\n type: \"string\",\n description: \"Instrument ID filter.\",\n },\n ordId: {\n type: \"string\",\n description: \"Order ID filter.\",\n },\n after: {\n type: \"string\",\n description: \"Pagination cursor: fills earlier than this bill ID.\",\n },\n before: {\n type: \"string\",\n description: \"Pagination cursor: fills newer than this bill ID.\",\n },\n begin: {\n type: \"string\",\n description: \"Start time filter in milliseconds.\",\n },\n end: {\n type: \"string\",\n description: \"End time filter in milliseconds.\",\n },\n limit: {\n type: \"number\",\n description: \"Number of results, max 100. Defaults to 100 (recent) or 20 (archive).\",\n },\n },\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const archive = readBoolean(args, \"archive\") ?? false;\n const instType = readString(args, \"instType\") ?? \"SWAP\";\n assertEnum(instType, \"instType\", SWAP_INST_TYPES);\n const path = archive ? \"/api/v5/trade/fills-history\" : \"/api/v5/trade/fills\";\n const response = await context.client.privateGet(\n path,\n compactObject({\n instType,\n instId: readString(args, \"instId\"),\n ordId: readString(args, \"ordId\"),\n after: readString(args, \"after\"),\n before: readString(args, \"before\"),\n begin: readString(args, \"begin\"),\n end: readString(args, \"end\"),\n limit: readNumber(args, \"limit\") ?? (archive ? 20 : undefined),\n }),\n privateRateLimit(\"swap_get_fills\", 20),\n );\n return normalize(response);\n },\n },\n {\n name: \"swap_get_order\",\n module: \"swap\",\n description:\n \"Get details of a single SWAP or FUTURES order by order ID or client order ID. Private endpoint. Rate limit: 60 req/s.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n instId: {\n type: \"string\",\n description: \"Instrument ID, e.g. BTC-USDT-SWAP.\",\n },\n ordId: {\n type: \"string\",\n description: \"Order ID. Provide either ordId or clOrdId.\",\n },\n clOrdId: {\n type: \"string\",\n description: \"Client-supplied order ID. Provide either ordId or clOrdId.\",\n },\n },\n required: [\"instId\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.privateGet(\n \"/api/v5/trade/order\",\n compactObject({\n instId: requireString(args, \"instId\"),\n ordId: readString(args, \"ordId\"),\n clOrdId: readString(args, \"clOrdId\"),\n }),\n privateRateLimit(\"swap_get_order\", 60),\n );\n return normalize(response);\n },\n },\n {\n name: \"swap_close_position\",\n module: \"swap\",\n description:\n \"[CAUTION] Close an entire SWAP/FUTURES position at market. Simpler than swap_place_order with reduceOnly when closing the full position. Private. Rate limit: 20 req/s.\",\n isWrite: true,\n inputSchema: {\n type: \"object\",\n properties: {\n instId: {\n type: \"string\",\n description: \"Instrument ID, e.g. BTC-USDT-SWAP.\",\n },\n mgnMode: {\n type: \"string\",\n enum: [\"cross\", \"isolated\"],\n description: \"Margin mode of the position to close.\",\n },\n posSide: {\n type: \"string\",\n enum: [\"long\", \"short\", \"net\"],\n description:\n \"Position side. Required in hedge mode (long/short). Omit for one-way mode (net).\",\n },\n autoCxl: {\n type: \"boolean\",\n description:\n \"Whether to cancel pending orders for the instrument when closing. Default false.\",\n },\n clOrdId: {\n type: \"string\",\n description: \"Client-supplied order ID for the close order.\",\n },\n tag: {\n type: \"string\",\n description: \"Order tag.\",\n },\n },\n required: [\"instId\", \"mgnMode\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const autoCxl = args.autoCxl;\n const response = await context.client.privatePost(\n \"/api/v5/trade/close-position\",\n compactObject({\n instId: requireString(args, \"instId\"),\n mgnMode: requireString(args, \"mgnMode\"),\n posSide: readString(args, \"posSide\"),\n autoCxl: typeof autoCxl === \"boolean\" ? String(autoCxl) : undefined,\n clOrdId: readString(args, \"clOrdId\"),\n tag: readString(args, \"tag\"),\n }),\n privateRateLimit(\"swap_close_position\", 20),\n );\n return normalize(response);\n },\n },\n {\n name: \"swap_batch_orders\",\n module: \"swap\",\n description:\n \"[CAUTION] Batch place/cancel/amend up to 20 SWAP/FUTURES orders in one request. Use action='place'/'cancel'/'amend'. Private. Rate limit: 60 req/s.\",\n isWrite: true,\n inputSchema: {\n type: \"object\",\n properties: {\n action: {\n type: \"string\",\n enum: [\"place\", \"cancel\", \"amend\"],\n description:\n \"Operation type. 'place': batch place orders. 'cancel': batch cancel by ordId/clOrdId. 'amend': batch modify newSz/newPx.\",\n },\n orders: {\n type: \"array\",\n description:\n \"Array of order objects (max 20). For 'place': {instId, tdMode, side, ordType, sz, px?, posSide?, reduceOnly?, clOrdId?, tpTriggerPx?, tpOrdPx?, slTriggerPx?, slOrdPx?}. For 'cancel': {instId, ordId} or {instId, clOrdId}. For 'amend': {instId, ordId or clOrdId, newSz?, newPx?}.\",\n items: {\n type: \"object\",\n },\n },\n },\n required: [\"action\", \"orders\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const action = requireString(args, \"action\");\n assertEnum(action, \"action\", [\"place\", \"cancel\", \"amend\"]);\n const orders = args.orders;\n if (!Array.isArray(orders) || orders.length === 0) {\n throw new Error(\"orders must be a non-empty array.\");\n }\n const endpointMap: Record<string, string> = {\n place: \"/api/v5/trade/batch-orders\",\n cancel: \"/api/v5/trade/cancel-batch-orders\",\n amend: \"/api/v5/trade/amend-batch-orders\",\n };\n const body: Record<string, unknown>[] =\n action === \"place\"\n ? orders.map((order: unknown) => {\n const o = asRecord(order);\n const tpTriggerPx = readString(o, \"tpTriggerPx\");\n const tpOrdPx = readString(o, \"tpOrdPx\");\n const slTriggerPx = readString(o, \"slTriggerPx\");\n const slOrdPx = readString(o, \"slOrdPx\");\n const algoEntry = compactObject({ tpTriggerPx, tpOrdPx, slTriggerPx, slOrdPx });\n const attachAlgoOrds =\n Object.keys(algoEntry).length > 0 ? [algoEntry] : undefined;\n const reduceOnly = o.reduceOnly;\n return compactObject({\n instId: requireString(o, \"instId\"),\n tdMode: requireString(o, \"tdMode\"),\n side: requireString(o, \"side\"),\n ordType: requireString(o, \"ordType\"),\n sz: requireString(o, \"sz\"),\n px: readString(o, \"px\"),\n posSide: readString(o, \"posSide\"),\n reduceOnly:\n typeof reduceOnly === \"boolean\" ? String(reduceOnly) : undefined,\n clOrdId: readString(o, \"clOrdId\"),\n attachAlgoOrds,\n });\n })\n : (orders as Record<string, unknown>[]);\n const response = await context.client.privatePost(\n endpointMap[action],\n body,\n privateRateLimit(\"swap_batch_orders\", 60),\n );\n return normalize(response);\n },\n },\n {\n name: \"swap_get_leverage\",\n module: \"swap\",\n description:\n \"Get current leverage for a SWAP/FUTURES instrument. Call before swap_place_order to verify leverage. Private. Rate limit: 20 req/s.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n instId: {\n type: \"string\",\n description: \"Instrument ID, e.g. BTC-USDT-SWAP.\",\n },\n mgnMode: {\n type: \"string\",\n enum: [\"cross\", \"isolated\"],\n description: \"Margin mode.\",\n },\n },\n required: [\"instId\", \"mgnMode\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.privateGet(\n \"/api/v5/account/leverage-info\",\n compactObject({\n instId: requireString(args, \"instId\"),\n mgnMode: requireString(args, \"mgnMode\"),\n }),\n privateRateLimit(\"swap_get_leverage\", 20),\n );\n return normalize(response);\n },\n },\n {\n name: \"swap_batch_amend\",\n module: \"swap\",\n description:\n \"[CAUTION] Batch amend up to 20 unfilled SWAP/FUTURES orders in one request. Modify price and/or size per order. Private endpoint. Rate limit: 60 req/s.\",\n isWrite: true,\n inputSchema: {\n type: \"object\",\n properties: {\n orders: {\n type: \"array\",\n description:\n \"Array of orders to amend (max 20). Each item: {instId: string, ordId?: string, clOrdId?: string, newSz?: string, newPx?: string}.\",\n items: { type: \"object\" },\n },\n },\n required: [\"orders\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const orders = args.orders;\n if (!Array.isArray(orders) || orders.length === 0) {\n throw new Error(\"orders must be a non-empty array.\");\n }\n const response = await context.client.privatePost(\n \"/api/v5/trade/amend-batch-orders\",\n orders as Record<string, unknown>[],\n privateRateLimit(\"swap_batch_amend\", 60),\n );\n return normalize(response);\n },\n },\n {\n name: \"swap_batch_cancel\",\n module: \"swap\",\n description:\n \"[CAUTION] Batch cancel up to 20 SWAP/FUTURES orders in one request. Provide instId plus ordId or clOrdId for each order. Private endpoint. Rate limit: 60 req/s.\",\n isWrite: true,\n inputSchema: {\n type: \"object\",\n properties: {\n orders: {\n type: \"array\",\n description:\n \"Array of orders to cancel (max 20). Each item: {instId: string, ordId?: string, clOrdId?: string}.\",\n items: { type: \"object\" },\n },\n },\n required: [\"orders\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const orders = args.orders;\n if (!Array.isArray(orders) || orders.length === 0) {\n throw new Error(\"orders must be a non-empty array.\");\n }\n const response = await context.client.privatePost(\n \"/api/v5/trade/cancel-batch-orders\",\n orders as Record<string, unknown>[],\n privateRateLimit(\"swap_batch_cancel\", 60),\n );\n return normalize(response);\n },\n },\n ];\n}\n","import type { OkxConfig } from \"../config.js\";\nimport { registerAccountTools } from \"./account.js\";\nimport { registerAlgoTradeTools } from \"./algo-trade.js\";\nimport { registerAuditTools } from \"./audit.js\";\nimport { registerBotTools } from \"./bot/index.js\";\nimport { registerFuturesTools } from \"./futures-trade.js\";\nimport { registerMarketTools } from \"./market.js\";\nimport { registerSpotTradeTools } from \"./spot-trade.js\";\nimport { registerSwapTradeTools } from \"./swap-trade.js\";\nimport type { ToolSpec } from \"./types.js\";\n\nfunction allToolSpecs(): ToolSpec[] {\n return [\n ...registerMarketTools(),\n ...registerSpotTradeTools(),\n ...registerSwapTradeTools(),\n ...registerFuturesTools(),\n ...registerAlgoTradeTools(),\n ...registerAccountTools(),\n ...registerBotTools(),\n ...registerAuditTools(),\n ];\n}\n\nexport function buildTools(config: OkxConfig): ToolSpec[] {\n const enabledModules = new Set(config.modules);\n const tools = allToolSpecs().filter((tool) => enabledModules.has(tool.module));\n if (!config.readOnly) {\n return tools;\n }\n return tools.filter((tool) => !tool.isWrite);\n}\n","import type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\nimport type { OkxRestClient } from \"../client/rest-client.js\";\nimport type { OkxConfig } from \"../config.js\";\nimport type { ModuleId } from \"../constants.js\";\n\nexport type ToolArgs = Record<string, unknown>;\n\nexport type JsonSchema = Tool[\"inputSchema\"];\n\nexport interface ToolContext {\n config: OkxConfig;\n client: OkxRestClient;\n}\n\nexport interface ToolSpec {\n name: string;\n module: ModuleId;\n description: string;\n inputSchema: JsonSchema;\n isWrite: boolean;\n handler: (args: ToolArgs, context: ToolContext) => Promise<unknown>;\n}\n\nexport function toMcpTool(tool: ToolSpec): Tool {\n return {\n name: tool.name,\n description: tool.description,\n inputSchema: tool.inputSchema,\n annotations: {\n readOnlyHint: !tool.isWrite,\n destructiveHint: tool.isWrite,\n idempotentHint: !tool.isWrite,\n openWorldHint: true,\n },\n };\n}\n","export const OKX_API_BASE_URL = \"https://www.okx.com\";\n\nexport const MODULES = [\n \"market\",\n \"spot\",\n \"swap\",\n \"futures\",\n \"account\",\n \"bot\",\n] as const;\n\nexport type ModuleId = (typeof MODULES)[number];\n\nexport const DEFAULT_MODULES: ModuleId[] = [\"spot\", \"swap\", \"account\"];\n","import { readFileSync, existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { parse } from \"smol-toml\";\n\nexport interface OkxProfile {\n api_key?: string;\n secret_key?: string;\n passphrase?: string;\n base_url?: string;\n timeout_ms?: number;\n demo?: boolean;\n}\n\nexport interface OkxTomlConfig {\n default_profile?: string;\n profiles: Record<string, OkxProfile>;\n}\n\nexport function configFilePath(): string {\n return join(homedir(), \".okx\", \"config.toml\");\n}\n\n/**\n * Read a profile from ~/.okx/config.toml.\n * Returns an empty object if the file does not exist or the profile is not found.\n */\nexport function readTomlProfile(profileName?: string): OkxProfile {\n const path = configFilePath();\n if (!existsSync(path)) return {};\n\n const raw = readFileSync(path, \"utf-8\");\n const config = parse(raw) as unknown as OkxTomlConfig;\n\n const name = profileName ?? config.default_profile ?? \"default\";\n return config.profiles?.[name] ?? {};\n}\n","import { DEFAULT_MODULES, MODULES, OKX_API_BASE_URL, type ModuleId } from \"./constants.js\";\nimport { ConfigError } from \"./utils/errors.js\";\nimport { readTomlProfile } from \"./config/toml.js\";\n\nexport interface CliOptions {\n modules?: string;\n readOnly: boolean;\n demo: boolean;\n profile?: string;\n userAgent?: string;\n}\n\nexport interface OkxConfig {\n apiKey?: string;\n secretKey?: string;\n passphrase?: string;\n hasAuth: boolean;\n baseUrl: string;\n timeoutMs: number;\n modules: ModuleId[];\n readOnly: boolean;\n demo: boolean;\n userAgent?: string;\n}\n\nfunction parseModuleList(rawModules?: string): ModuleId[] {\n if (!rawModules || rawModules.trim().length === 0) {\n return [...DEFAULT_MODULES];\n }\n\n const trimmed = rawModules.trim().toLowerCase();\n if (trimmed === \"all\") {\n return [...MODULES];\n }\n\n const requested = trimmed\n .split(\",\")\n .map((item) => item.trim())\n .filter((item) => item.length > 0);\n\n if (requested.length === 0) {\n return [...DEFAULT_MODULES];\n }\n\n const deduped = new Set<ModuleId>();\n for (const moduleId of requested) {\n if (!MODULES.includes(moduleId as ModuleId)) {\n throw new ConfigError(\n `Unknown module \"${moduleId}\".`,\n `Use one of: ${MODULES.join(\", \")} or \"all\".`,\n );\n }\n deduped.add(moduleId as ModuleId);\n }\n\n return Array.from(deduped);\n}\n\n/**\n * Credential priority (highest to lowest):\n * 1. Environment variables (OKX_API_KEY / OKX_SECRET_KEY / OKX_PASSPHRASE)\n * 2. ~/.okx/config.toml — profile selected by cli.profile or default_profile\n */\nexport function loadConfig(cli: CliOptions): OkxConfig {\n // Read toml profile as fallback\n const toml = readTomlProfile(cli.profile);\n\n const apiKey = process.env.OKX_API_KEY?.trim() ?? toml.api_key;\n const secretKey = process.env.OKX_SECRET_KEY?.trim() ?? toml.secret_key;\n const passphrase = process.env.OKX_PASSPHRASE?.trim() ?? toml.passphrase;\n\n const hasAuth = Boolean(apiKey && secretKey && passphrase);\n const partialAuth = Boolean(apiKey) || Boolean(secretKey) || Boolean(passphrase);\n\n if (partialAuth && !hasAuth) {\n throw new ConfigError(\n \"Partial API credentials detected.\",\n \"Set OKX_API_KEY, OKX_SECRET_KEY and OKX_PASSPHRASE together (env vars or config.toml profile).\",\n );\n }\n\n // demo flag: cli arg > env var > toml profile\n const demo =\n cli.demo ||\n process.env.OKX_DEMO === \"1\" ||\n process.env.OKX_DEMO === \"true\" ||\n (toml.demo ?? false);\n\n // base url: env var > toml profile > default\n const rawBaseUrl =\n process.env.OKX_API_BASE_URL?.trim() ?? toml.base_url ?? OKX_API_BASE_URL;\n if (!rawBaseUrl.startsWith(\"http://\") && !rawBaseUrl.startsWith(\"https://\")) {\n throw new ConfigError(\n `Invalid base URL \"${rawBaseUrl}\".`,\n \"OKX_API_BASE_URL must start with http:// or https://\",\n );\n }\n const baseUrl = rawBaseUrl.replace(/\\/+$/, \"\");\n\n // timeout: env var > toml profile > default\n const rawTimeout = process.env.OKX_TIMEOUT_MS\n ? Number(process.env.OKX_TIMEOUT_MS)\n : (toml.timeout_ms ?? 15_000);\n if (!Number.isFinite(rawTimeout) || rawTimeout <= 0) {\n throw new ConfigError(\n `Invalid timeout value \"${rawTimeout}\".`,\n \"Set OKX_TIMEOUT_MS as a positive integer in milliseconds.\",\n );\n }\n\n return {\n apiKey,\n secretKey,\n passphrase,\n hasAuth,\n baseUrl,\n timeoutMs: Math.floor(rawTimeout),\n modules: parseModuleList(cli.modules),\n readOnly: cli.readOnly,\n demo,\n userAgent: cli.userAgent,\n };\n}\n","import { readFileSync, writeFileSync, mkdirSync, existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\n\nconst CACHE_FILE = join(homedir(), \".okx\", \"update-check.json\");\nconst CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000; // 24 hours\n\ninterface PackageCache {\n latestVersion: string;\n checkedAt: number;\n}\n\ntype UpdateCache = Record<string, PackageCache>;\n\nfunction readCache(): UpdateCache {\n try {\n if (existsSync(CACHE_FILE)) {\n return JSON.parse(readFileSync(CACHE_FILE, \"utf-8\")) as UpdateCache;\n }\n } catch {\n // ignore corrupt cache\n }\n return {};\n}\n\nfunction writeCache(cache: UpdateCache): void {\n try {\n mkdirSync(join(homedir(), \".okx\"), { recursive: true });\n writeFileSync(CACHE_FILE, JSON.stringify(cache, null, 2), \"utf-8\");\n } catch {\n // ignore write failures\n }\n}\n\nfunction isNewerVersion(current: string, latest: string): boolean {\n const parse = (v: string) =>\n v\n .replace(/^v/, \"\")\n .split(\".\")\n .map((n) => parseInt(n, 10));\n const [cMaj, cMin, cPat] = parse(current);\n const [lMaj, lMin, lPat] = parse(latest);\n if (lMaj !== cMaj) return lMaj > cMaj;\n if (lMin !== cMin) return lMin > cMin;\n return lPat > cPat;\n}\n\nasync function fetchLatestVersion(packageName: string): Promise<string | null> {\n try {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 3000);\n const res = await fetch(`https://registry.npmjs.org/${encodeURIComponent(packageName)}/latest`, {\n signal: controller.signal,\n headers: { accept: \"application/json\" },\n });\n clearTimeout(timeout);\n if (!res.ok) return null;\n const data = (await res.json()) as { version: string };\n return data.version ?? null;\n } catch {\n return null;\n }\n}\n\nfunction refreshCacheInBackground(packageName: string): void {\n fetchLatestVersion(packageName)\n .then((latest) => {\n if (!latest) return;\n const cache = readCache();\n cache[packageName] = { latestVersion: latest, checkedAt: Date.now() };\n writeCache(cache);\n })\n .catch(() => {\n // ignore\n });\n}\n\n/**\n * Check if an update is available and print a notice to stderr.\n * Uses a local cache (~/.okx/update-check.json) so network calls happen\n * at most once per 24 hours, in the background without blocking startup.\n */\nexport function checkForUpdates(packageName: string, currentVersion: string): void {\n const cache = readCache();\n const entry = cache[packageName];\n\n if (entry && isNewerVersion(currentVersion, entry.latestVersion)) {\n process.stderr.write(\n `\\nUpdate available for ${packageName}: ${currentVersion} → ${entry.latestVersion}\\n` +\n `Run: npm install -g ${packageName}\\n\\n`,\n );\n }\n\n if (!entry || Date.now() - entry.checkedAt > CHECK_INTERVAL_MS) {\n refreshCacheInBackground(packageName);\n }\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport os from \"node:os\";\n\nexport type LogLevel = \"error\" | \"warn\" | \"info\" | \"debug\";\n\nconst LOG_LEVEL_PRIORITY: Record<LogLevel, number> = {\n error: 0,\n warn: 1,\n info: 2,\n debug: 3,\n};\n\nconst SENSITIVE_KEY_PATTERN = /apiKey|secretKey|passphrase|password|secret/i;\n\nfunction sanitize(value: unknown): unknown {\n if (value === null || value === undefined) {\n return value;\n }\n if (Array.isArray(value)) {\n return value.map(sanitize);\n }\n if (typeof value === \"object\") {\n const result: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n if (SENSITIVE_KEY_PATTERN.test(k)) {\n result[k] = \"[REDACTED]\";\n } else {\n result[k] = sanitize(v);\n }\n }\n return result;\n }\n return value;\n}\n\nexport interface LogEntry {\n timestamp: string;\n level: Uppercase<LogLevel>;\n tool: string;\n durationMs: number;\n params: unknown;\n result: unknown;\n}\n\nexport class TradeLogger {\n private readonly logLevel: LogLevel;\n private readonly logDir: string;\n\n constructor(logLevel: LogLevel = \"info\", logDir?: string) {\n this.logLevel = logLevel;\n this.logDir = logDir ?? path.join(os.homedir(), \".okx\", \"logs\");\n }\n\n getLogPath(date?: Date): string {\n const d = date ?? new Date();\n const yyyy = d.getUTCFullYear();\n const mm = String(d.getUTCMonth() + 1).padStart(2, \"0\");\n const dd = String(d.getUTCDate()).padStart(2, \"0\");\n return path.join(this.logDir, `trade-${yyyy}-${mm}-${dd}.log`);\n }\n\n log(\n level: LogLevel,\n tool: string,\n params: unknown,\n result: unknown,\n durationMs: number,\n ): void {\n if (LOG_LEVEL_PRIORITY[level] > LOG_LEVEL_PRIORITY[this.logLevel]) {\n return;\n }\n\n const entry: LogEntry = {\n timestamp: new Date().toISOString(),\n level: level.toUpperCase() as Uppercase<LogLevel>,\n tool,\n durationMs,\n params: sanitize(params),\n result: sanitize(result),\n };\n\n try {\n fs.mkdirSync(this.logDir, { recursive: true });\n fs.appendFileSync(this.getLogPath(), JSON.stringify(entry) + \"\\n\", \"utf8\");\n } catch {\n // silent fail\n }\n }\n\n static sanitize(params: unknown): unknown {\n return sanitize(params);\n }\n}\n","import type { OkxConfig } from \"@okx-hub/core\";\nimport { loadConfig } from \"@okx-hub/core\";\n\nexport interface LoadProfileOptions {\n profile?: string;\n modules?: string;\n readOnly?: boolean;\n demo?: boolean;\n userAgent?: string;\n}\n\n/**\n * Load config for CLI commands.\n * Delegates to core's loadConfig which handles the full priority chain:\n * env vars > ~/.okx/config.toml (selected profile) > defaults\n */\nexport function loadProfileConfig(opts: LoadProfileOptions): OkxConfig {\n return loadConfig({\n profile: opts.profile,\n modules: opts.modules,\n readOnly: opts.readOnly ?? false,\n demo: opts.demo ?? false,\n userAgent: opts.userAgent,\n });\n}\n","export function printJson(data: unknown): void {\n process.stdout.write(JSON.stringify(data, null, 2) + \"\\n\");\n}\n\nexport function printTable(rows: Record<string, unknown>[]): void {\n if (rows.length === 0) {\n process.stdout.write(\"(no data)\\n\");\n return;\n }\n const keys = Object.keys(rows[0]);\n const widths = keys.map((k) =>\n Math.max(k.length, ...rows.map((r) => String(r[k] ?? \"\").length)),\n );\n const header = keys.map((k, i) => k.padEnd(widths[i])).join(\" \");\n const divider = widths.map((w) => \"-\".repeat(w)).join(\" \");\n process.stdout.write(header + \"\\n\" + divider + \"\\n\");\n for (const row of rows) {\n process.stdout.write(\n keys.map((k, i) => String(row[k] ?? \"\").padEnd(widths[i])).join(\" \") + \"\\n\",\n );\n }\n}\n\nexport function printKv(obj: Record<string, unknown>, indent = 0): void {\n const pad = \" \".repeat(indent);\n for (const [k, v] of Object.entries(obj)) {\n if (v !== null && typeof v === \"object\" && !Array.isArray(v)) {\n process.stdout.write(`${pad}${k}:\\n`);\n printKv(v as Record<string, unknown>, indent + 2);\n } else {\n process.stdout.write(`${pad}${k.padEnd(20 - indent)} ${v}\\n`);\n }\n }\n}\n","import type { OkxRestClient } from \"@okx-hub/core\";\nimport { printJson, printKv, printTable } from \"../formatter.js\";\n\nexport async function cmdMarketInstruments(\n client: OkxRestClient,\n opts: { instType: string; instId?: string; json: boolean },\n): Promise<void> {\n const params: Record<string, unknown> = { instType: opts.instType };\n if (opts.instId) params[\"instId\"] = opts.instId;\n const res = await client.publicGet(\"/api/v5/public/instruments\", params);\n const items = res.data as Record<string, unknown>[];\n if (opts.json) return printJson(items);\n printTable(\n (items ?? []).slice(0, 50).map((t) => ({\n instId: t[\"instId\"],\n ctVal: t[\"ctVal\"],\n lotSz: t[\"lotSz\"],\n minSz: t[\"minSz\"],\n tickSz: t[\"tickSz\"],\n state: t[\"state\"],\n })),\n );\n}\n\nexport async function cmdMarketFundingRate(\n client: OkxRestClient,\n instId: string,\n opts: { history: boolean; limit?: number; json: boolean },\n): Promise<void> {\n if (opts.history) {\n const params: Record<string, unknown> = { instId };\n if (opts.limit) params[\"limit\"] = String(opts.limit);\n const res = await client.publicGet(\"/api/v5/public/funding-rate-history\", params);\n const items = res.data as Record<string, unknown>[];\n if (opts.json) return printJson(items);\n printTable(\n (items ?? []).map((r) => ({\n instId: r[\"instId\"],\n fundingRate: r[\"fundingRate\"],\n realizedRate: r[\"realizedRate\"],\n fundingTime: new Date(Number(r[\"fundingTime\"])).toLocaleString(),\n })),\n );\n } else {\n const res = await client.publicGet(\"/api/v5/public/funding-rate\", { instId });\n const items = res.data as Record<string, unknown>[];\n if (opts.json) return printJson(items);\n const r = items?.[0];\n if (!r) { process.stdout.write(\"No data\\n\"); return; }\n printKv({\n instId: r[\"instId\"],\n fundingRate: r[\"fundingRate\"],\n nextFundingRate: r[\"nextFundingRate\"],\n fundingTime: new Date(Number(r[\"fundingTime\"])).toLocaleString(),\n nextFundingTime: new Date(Number(r[\"nextFundingTime\"])).toLocaleString(),\n });\n }\n}\n\nexport async function cmdMarketMarkPrice(\n client: OkxRestClient,\n opts: { instType: string; instId?: string; json: boolean },\n): Promise<void> {\n const params: Record<string, unknown> = { instType: opts.instType };\n if (opts.instId) params[\"instId\"] = opts.instId;\n const res = await client.publicGet(\"/api/v5/public/mark-price\", params);\n const items = res.data as Record<string, unknown>[];\n if (opts.json) return printJson(items);\n printTable(\n (items ?? []).map((r) => ({\n instId: r[\"instId\"],\n instType: r[\"instType\"],\n markPx: r[\"markPx\"],\n ts: new Date(Number(r[\"ts\"])).toLocaleString(),\n })),\n );\n}\n\nexport async function cmdMarketTrades(\n client: OkxRestClient,\n instId: string,\n opts: { limit?: number; json: boolean },\n): Promise<void> {\n const params: Record<string, unknown> = { instId };\n if (opts.limit) params[\"limit\"] = String(opts.limit);\n const res = await client.publicGet(\"/api/v5/market/trades\", params);\n const items = res.data as Record<string, unknown>[];\n if (opts.json) return printJson(items);\n printTable(\n (items ?? []).map((t) => ({\n tradeId: t[\"tradeId\"],\n px: t[\"px\"],\n sz: t[\"sz\"],\n side: t[\"side\"],\n ts: new Date(Number(t[\"ts\"])).toLocaleString(),\n })),\n );\n}\n\nexport async function cmdMarketIndexTicker(\n client: OkxRestClient,\n opts: { instId?: string; quoteCcy?: string; json: boolean },\n): Promise<void> {\n const params: Record<string, unknown> = {};\n if (opts.instId) params[\"instId\"] = opts.instId;\n if (opts.quoteCcy) params[\"quoteCcy\"] = opts.quoteCcy;\n const res = await client.publicGet(\"/api/v5/market/index-tickers\", params);\n const items = res.data as Record<string, unknown>[];\n if (opts.json) return printJson(items);\n printTable(\n (items ?? []).map((t) => ({\n instId: t[\"instId\"],\n idxPx: t[\"idxPx\"],\n high24h: t[\"high24h\"],\n low24h: t[\"low24h\"],\n ts: new Date(Number(t[\"ts\"])).toLocaleString(),\n })),\n );\n}\n\nexport async function cmdMarketIndexCandles(\n client: OkxRestClient,\n instId: string,\n opts: { bar?: string; limit?: number; history: boolean; json: boolean },\n): Promise<void> {\n const path = opts.history\n ? \"/api/v5/market/history-index-candles\"\n : \"/api/v5/market/index-candles\";\n const params: Record<string, unknown> = { instId };\n if (opts.bar) params[\"bar\"] = opts.bar;\n if (opts.limit) params[\"limit\"] = String(opts.limit);\n const res = await client.publicGet(path, params);\n const candles = res.data as string[][];\n if (opts.json) return printJson(candles);\n printTable(\n (candles ?? []).map(([ts, o, h, l, c]) => ({\n time: new Date(Number(ts)).toLocaleString(),\n open: o, high: h, low: l, close: c,\n })),\n );\n}\n\nexport async function cmdMarketPriceLimit(\n client: OkxRestClient,\n instId: string,\n json: boolean,\n): Promise<void> {\n const res = await client.publicGet(\"/api/v5/public/price-limit\", { instId });\n const items = res.data as Record<string, unknown>[];\n if (json) return printJson(items);\n const r = items?.[0];\n if (!r) { process.stdout.write(\"No data\\n\"); return; }\n printKv({\n instId: r[\"instId\"],\n buyLmt: r[\"buyLmt\"],\n sellLmt: r[\"sellLmt\"],\n ts: new Date(Number(r[\"ts\"])).toLocaleString(),\n });\n}\n\nexport async function cmdMarketOpenInterest(\n client: OkxRestClient,\n opts: { instType: string; instId?: string; json: boolean },\n): Promise<void> {\n const params: Record<string, unknown> = { instType: opts.instType };\n if (opts.instId) params[\"instId\"] = opts.instId;\n const res = await client.publicGet(\"/api/v5/public/open-interest\", params);\n const items = res.data as Record<string, unknown>[];\n if (opts.json) return printJson(items);\n printTable(\n (items ?? []).map((r) => ({\n instId: r[\"instId\"],\n oi: r[\"oi\"],\n oiCcy: r[\"oiCcy\"],\n ts: new Date(Number(r[\"ts\"])).toLocaleString(),\n })),\n );\n}\n\nexport async function cmdMarketTicker(\n client: OkxRestClient,\n instId: string,\n json: boolean,\n): Promise<void> {\n const res = await client.publicGet(\"/api/v5/market/ticker\", { instId });\n const items = res.data as Record<string, unknown>[];\n if (json) return printJson(items);\n if (!items?.length) { process.stdout.write(\"No data\\n\"); return; }\n const t = items[0];\n printKv({\n instId: t[\"instId\"],\n last: t[\"last\"],\n \"24h change %\": t[\"sodUtc8\"],\n \"24h high\": t[\"high24h\"],\n \"24h low\": t[\"low24h\"],\n \"24h vol\": t[\"vol24h\"],\n time: new Date(Number(t[\"ts\"])).toLocaleString(),\n });\n}\n\nexport async function cmdMarketTickers(\n client: OkxRestClient,\n instType: string,\n json: boolean,\n): Promise<void> {\n const res = await client.publicGet(\"/api/v5/market/tickers\", { instType });\n const items = res.data as Record<string, unknown>[];\n if (json) return printJson(items);\n printTable(\n (items ?? []).map((t) => ({\n instId: t[\"instId\"],\n last: t[\"last\"],\n \"24h high\": t[\"high24h\"],\n \"24h low\": t[\"low24h\"],\n \"24h vol\": t[\"vol24h\"],\n })),\n );\n}\n\nexport async function cmdMarketOrderbook(\n client: OkxRestClient,\n instId: string,\n sz: number | undefined,\n json: boolean,\n): Promise<void> {\n const params: Record<string, unknown> = { instId };\n if (sz !== undefined) params[\"sz\"] = String(sz);\n const res = await client.publicGet(\"/api/v5/market/books\", params);\n if (json) return printJson(res.data);\n const book = (res.data as Record<string, unknown>[])[0];\n if (!book) { process.stdout.write(\"No data\\n\"); return; }\n const asks = (book[\"asks\"] as string[][]).slice(0, 5);\n const bids = (book[\"bids\"] as string[][]).slice(0, 5);\n process.stdout.write(\"Asks (price / size):\\n\");\n for (const [p, s] of asks.reverse()) process.stdout.write(` ${p.padStart(16)} ${s}\\n`);\n process.stdout.write(\"Bids (price / size):\\n\");\n for (const [p, s] of bids) process.stdout.write(` ${p.padStart(16)} ${s}\\n`);\n}\n\nexport async function cmdMarketCandles(\n client: OkxRestClient,\n instId: string,\n opts: { bar?: string; limit?: number; json: boolean },\n): Promise<void> {\n const params: Record<string, unknown> = { instId };\n if (opts.bar) params[\"bar\"] = opts.bar;\n if (opts.limit) params[\"limit\"] = String(opts.limit);\n const res = await client.publicGet(\"/api/v5/market/candles\", params);\n const candles = res.data as string[][];\n if (opts.json) return printJson(candles);\n printTable(\n (candles ?? []).map(([ts, o, h, l, c, vol]) => ({\n time: new Date(Number(ts)).toLocaleString(),\n open: o, high: h, low: l, close: c, vol,\n })),\n );\n}\n","import type { OkxRestClient } from \"@okx-hub/core\";\nimport { printJson, printKv, printTable } from \"../formatter.js\";\n\nexport async function cmdAccountBalance(\n client: OkxRestClient,\n ccy: string | undefined,\n json: boolean,\n): Promise<void> {\n const params: Record<string, unknown> = {};\n if (ccy) params[\"ccy\"] = ccy;\n const res = await client.privateGet(\"/api/v5/account/balance\", params);\n const data = res.data as Record<string, unknown>[];\n if (json) return printJson(data);\n const details = (data?.[0]?.[\"details\"] as Record<string, unknown>[]) ?? [];\n printTable(\n details\n .filter((d) => Number(d[\"eq\"]) > 0)\n .map((d) => ({\n currency: d[\"ccy\"],\n equity: d[\"eq\"],\n available: d[\"availEq\"],\n frozen: d[\"frozenBal\"],\n })),\n );\n}\n\nexport async function cmdAccountAssetBalance(\n client: OkxRestClient,\n ccy: string | undefined,\n json: boolean,\n): Promise<void> {\n const params: Record<string, unknown> = {};\n if (ccy) params[\"ccy\"] = ccy;\n const res = await client.privateGet(\"/api/v5/asset/balances\", params);\n const data = res.data as Record<string, unknown>[];\n if (json) return printJson(data);\n printTable(\n (data ?? [])\n .filter((r) => Number(r[\"bal\"]) > 0)\n .map((r) => ({\n ccy: r[\"ccy\"],\n bal: r[\"bal\"],\n availBal: r[\"availBal\"],\n frozenBal: r[\"frozenBal\"],\n })),\n );\n}\n\nexport async function cmdAccountPositions(\n client: OkxRestClient,\n opts: { instType?: string; instId?: string; json: boolean },\n): Promise<void> {\n const params: Record<string, unknown> = {};\n if (opts.instType) params[\"instType\"] = opts.instType;\n if (opts.instId) params[\"instId\"] = opts.instId;\n const res = await client.privateGet(\"/api/v5/account/positions\", params);\n const positions = res.data as Record<string, unknown>[];\n if (opts.json) return printJson(positions);\n const open = (positions ?? []).filter((p) => Number(p[\"pos\"]) !== 0);\n if (!open.length) { process.stdout.write(\"No open positions\\n\"); return; }\n printTable(\n open.map((p) => ({\n instId: p[\"instId\"],\n instType: p[\"instType\"],\n side: p[\"posSide\"],\n pos: p[\"pos\"],\n avgPx: p[\"avgPx\"],\n upl: p[\"upl\"],\n lever: p[\"lever\"],\n })),\n );\n}\n\nexport async function cmdAccountBills(\n client: OkxRestClient,\n opts: { archive: boolean; instType?: string; ccy?: string; limit?: number; json: boolean },\n): Promise<void> {\n const endpoint = opts.archive ? \"/api/v5/account/bills-archive\" : \"/api/v5/account/bills\";\n const params: Record<string, unknown> = {};\n if (opts.instType) params[\"instType\"] = opts.instType;\n if (opts.ccy) params[\"ccy\"] = opts.ccy;\n if (opts.limit) params[\"limit\"] = String(opts.limit);\n const res = await client.privateGet(endpoint, params);\n const bills = res.data as Record<string, unknown>[];\n if (opts.json) return printJson(bills);\n printTable(\n (bills ?? []).map((b) => ({\n billId: b[\"billId\"],\n instId: b[\"instId\"],\n type: b[\"type\"],\n ccy: b[\"ccy\"],\n balChg: b[\"balChg\"],\n bal: b[\"bal\"],\n ts: new Date(Number(b[\"ts\"])).toLocaleString(),\n })),\n );\n}\n\nexport async function cmdAccountFees(\n client: OkxRestClient,\n opts: { instType: string; instId?: string; json: boolean },\n): Promise<void> {\n const params: Record<string, unknown> = { instType: opts.instType };\n if (opts.instId) params[\"instId\"] = opts.instId;\n const res = await client.privateGet(\"/api/v5/account/trade-fee\", params);\n const data = res.data as Record<string, unknown>[];\n if (opts.json) return printJson(data);\n const fee = data?.[0];\n if (!fee) { process.stdout.write(\"No data\\n\"); return; }\n printKv({\n level: fee[\"level\"],\n maker: fee[\"maker\"],\n taker: fee[\"taker\"],\n makerU: fee[\"makerU\"],\n takerU: fee[\"takerU\"],\n ts: new Date(Number(fee[\"ts\"])).toLocaleString(),\n });\n}\n\nexport async function cmdAccountConfig(\n client: OkxRestClient,\n json: boolean,\n): Promise<void> {\n const res = await client.privateGet(\"/api/v5/account/config\", {});\n const data = res.data as Record<string, unknown>[];\n if (json) return printJson(data);\n const cfg = data?.[0];\n if (!cfg) { process.stdout.write(\"No data\\n\"); return; }\n printKv({\n uid: cfg[\"uid\"],\n acctLv: cfg[\"acctLv\"],\n posMode: cfg[\"posMode\"],\n autoLoan: cfg[\"autoLoan\"],\n greeksType: cfg[\"greeksType\"],\n level: cfg[\"level\"],\n levelTmp: cfg[\"levelTmp\"],\n });\n}\n\nexport async function cmdAccountSetPositionMode(\n client: OkxRestClient,\n posMode: string,\n json: boolean,\n): Promise<void> {\n const res = await client.privatePost(\"/api/v5/account/set-position-mode\", { posMode });\n if (json) return printJson(res.data);\n const r = (res.data as Record<string, unknown>[])[0];\n process.stdout.write(`Position mode set: ${r?.[\"posMode\"]}\\n`);\n}\n\nexport async function cmdAccountMaxSize(\n client: OkxRestClient,\n opts: { instId: string; tdMode: string; px?: string; json: boolean },\n): Promise<void> {\n const params: Record<string, unknown> = { instId: opts.instId, tdMode: opts.tdMode };\n if (opts.px) params[\"px\"] = opts.px;\n const res = await client.privateGet(\"/api/v5/account/max-size\", params);\n const data = res.data as Record<string, unknown>[];\n if (opts.json) return printJson(data);\n const r = data?.[0];\n if (!r) { process.stdout.write(\"No data\\n\"); return; }\n printKv({ instId: r[\"instId\"], maxBuy: r[\"maxBuy\"], maxSell: r[\"maxSell\"] });\n}\n\nexport async function cmdAccountMaxAvailSize(\n client: OkxRestClient,\n opts: { instId: string; tdMode: string; json: boolean },\n): Promise<void> {\n const res = await client.privateGet(\"/api/v5/account/max-avail-size\", {\n instId: opts.instId,\n tdMode: opts.tdMode,\n });\n const data = res.data as Record<string, unknown>[];\n if (opts.json) return printJson(data);\n const r = data?.[0];\n if (!r) { process.stdout.write(\"No data\\n\"); return; }\n printKv({ instId: r[\"instId\"], availBuy: r[\"availBuy\"], availSell: r[\"availSell\"] });\n}\n\nexport async function cmdAccountMaxWithdrawal(\n client: OkxRestClient,\n ccy: string | undefined,\n json: boolean,\n): Promise<void> {\n const params: Record<string, unknown> = {};\n if (ccy) params[\"ccy\"] = ccy;\n const res = await client.privateGet(\"/api/v5/account/max-withdrawal\", params);\n const data = res.data as Record<string, unknown>[];\n if (json) return printJson(data);\n printTable(\n (data ?? []).map((r) => ({\n ccy: r[\"ccy\"],\n maxWd: r[\"maxWd\"],\n maxWdEx: r[\"maxWdEx\"],\n })),\n );\n}\n\nexport async function cmdAccountPositionsHistory(\n client: OkxRestClient,\n opts: { instType?: string; instId?: string; limit?: number; json: boolean },\n): Promise<void> {\n const params: Record<string, unknown> = {};\n if (opts.instType) params[\"instType\"] = opts.instType;\n if (opts.instId) params[\"instId\"] = opts.instId;\n if (opts.limit) params[\"limit\"] = String(opts.limit);\n const res = await client.privateGet(\"/api/v5/account/positions-history\", params);\n const data = res.data as Record<string, unknown>[];\n if (opts.json) return printJson(data);\n printTable(\n (data ?? []).map((p) => ({\n instId: p[\"instId\"],\n direction: p[\"direction\"],\n openAvgPx: p[\"openAvgPx\"],\n closeAvgPx: p[\"closeAvgPx\"],\n realizedPnl: p[\"realizedPnl\"],\n uTime: new Date(Number(p[\"uTime\"])).toLocaleString(),\n })),\n );\n}\n\nexport async function cmdAccountTransfer(\n client: OkxRestClient,\n opts: {\n ccy: string;\n amt: string;\n from: string;\n to: string;\n transferType?: string;\n subAcct?: string;\n json: boolean;\n },\n): Promise<void> {\n const body: Record<string, unknown> = {\n ccy: opts.ccy,\n amt: opts.amt,\n from: opts.from,\n to: opts.to,\n };\n if (opts.transferType) body[\"type\"] = opts.transferType;\n if (opts.subAcct) body[\"subAcct\"] = opts.subAcct;\n const res = await client.privatePost(\"/api/v5/asset/transfer\", body);\n if (opts.json) return printJson(res.data);\n const r = (res.data as Record<string, unknown>[])[0];\n process.stdout.write(`Transfer: ${r?.[\"transId\"]} (${r?.[\"ccy\"]} ${r?.[\"amt\"]})\\n`);\n}\n","import type { OkxRestClient } from \"@okx-hub/core\";\nimport { printJson, printKv, printTable } from \"../formatter.js\";\n\nexport async function cmdSpotOrders(\n client: OkxRestClient,\n opts: { instId?: string; status: \"open\" | \"history\"; json: boolean },\n): Promise<void> {\n const endpoint =\n opts.status === \"history\"\n ? \"/api/v5/trade/orders-history\"\n : \"/api/v5/trade/orders-pending\";\n const params: Record<string, unknown> = { instType: \"SPOT\" };\n if (opts.instId) params[\"instId\"] = opts.instId;\n const res = await client.privateGet(endpoint, params);\n const orders = res.data as Record<string, unknown>[];\n if (opts.json) return printJson(orders);\n printTable(\n (orders ?? []).map((o) => ({\n ordId: o[\"ordId\"],\n instId: o[\"instId\"],\n side: o[\"side\"],\n type: o[\"ordType\"],\n price: o[\"px\"],\n size: o[\"sz\"],\n filled: o[\"fillSz\"],\n state: o[\"state\"],\n })),\n );\n}\n\nexport async function cmdSpotPlace(\n client: OkxRestClient,\n opts: {\n instId: string;\n side: string;\n ordType: string;\n sz: string;\n px?: string;\n json: boolean;\n },\n): Promise<void> {\n const body: Record<string, unknown> = {\n instId: opts.instId,\n tdMode: \"cash\",\n side: opts.side,\n ordType: opts.ordType,\n sz: opts.sz,\n };\n if (opts.px) body[\"px\"] = opts.px;\n const res = await client.privatePost(\"/api/v5/trade/order\", body);\n if (opts.json) return printJson(res.data);\n const order = (res.data as Record<string, unknown>[])[0];\n process.stdout.write(`Order placed: ${order?.[\"ordId\"]} (${order?.[\"sCode\"] === \"0\" ? \"OK\" : order?.[\"sMsg\"]})\\n`);\n}\n\nexport async function cmdSpotCancel(\n client: OkxRestClient,\n instId: string,\n ordId: string,\n json: boolean,\n): Promise<void> {\n const res = await client.privatePost(\"/api/v5/trade/cancel-order\", { instId, ordId });\n if (json) return printJson(res.data);\n const r = (res.data as Record<string, unknown>[])[0];\n process.stdout.write(`Cancelled: ${r?.[\"ordId\"]} (${r?.[\"sCode\"] === \"0\" ? \"OK\" : r?.[\"sMsg\"]})\\n`);\n}\n\nexport async function cmdSpotAlgoPlace(\n client: OkxRestClient,\n opts: {\n instId: string;\n side: string;\n ordType: string;\n sz: string;\n tpTriggerPx?: string;\n tpOrdPx?: string;\n slTriggerPx?: string;\n slOrdPx?: string;\n json: boolean;\n },\n): Promise<void> {\n const body: Record<string, unknown> = {\n instId: opts.instId,\n tdMode: \"cash\",\n side: opts.side,\n ordType: opts.ordType,\n sz: opts.sz,\n };\n if (opts.tpTriggerPx) body[\"tpTriggerPx\"] = opts.tpTriggerPx;\n if (opts.tpOrdPx) body[\"tpOrdPx\"] = opts.tpOrdPx;\n if (opts.slTriggerPx) body[\"slTriggerPx\"] = opts.slTriggerPx;\n if (opts.slOrdPx) body[\"slOrdPx\"] = opts.slOrdPx;\n const res = await client.privatePost(\"/api/v5/trade/order-algo\", body);\n if (opts.json) return printJson(res.data);\n const order = (res.data as Record<string, unknown>[])[0];\n process.stdout.write(\n `Algo order placed: ${order?.[\"algoId\"]} (${order?.[\"sCode\"] === \"0\" ? \"OK\" : order?.[\"sMsg\"]})\\n`,\n );\n}\n\nexport async function cmdSpotAlgoAmend(\n client: OkxRestClient,\n opts: {\n instId: string;\n algoId: string;\n newSz?: string;\n newTpTriggerPx?: string;\n newTpOrdPx?: string;\n newSlTriggerPx?: string;\n newSlOrdPx?: string;\n json: boolean;\n },\n): Promise<void> {\n const body: Record<string, unknown> = {\n instId: opts.instId,\n algoId: opts.algoId,\n };\n if (opts.newSz) body[\"newSz\"] = opts.newSz;\n if (opts.newTpTriggerPx) body[\"newTpTriggerPx\"] = opts.newTpTriggerPx;\n if (opts.newTpOrdPx) body[\"newTpOrdPx\"] = opts.newTpOrdPx;\n if (opts.newSlTriggerPx) body[\"newSlTriggerPx\"] = opts.newSlTriggerPx;\n if (opts.newSlOrdPx) body[\"newSlOrdPx\"] = opts.newSlOrdPx;\n const res = await client.privatePost(\"/api/v5/trade/amend-algos\", body);\n if (opts.json) return printJson(res.data);\n const r = (res.data as Record<string, unknown>[])[0];\n process.stdout.write(\n `Algo order amended: ${r?.[\"algoId\"]} (${r?.[\"sCode\"] === \"0\" ? \"OK\" : r?.[\"sMsg\"]})\\n`,\n );\n}\n\nexport async function cmdSpotAlgoCancel(\n client: OkxRestClient,\n instId: string,\n algoId: string,\n json: boolean,\n): Promise<void> {\n const res = await client.privatePost(\"/api/v5/trade/cancel-algos\", [\n { algoId, instId },\n ]);\n if (json) return printJson(res.data);\n const r = (res.data as Record<string, unknown>[])[0];\n process.stdout.write(\n `Algo order cancelled: ${r?.[\"algoId\"]} (${r?.[\"sCode\"] === \"0\" ? \"OK\" : r?.[\"sMsg\"]})\\n`,\n );\n}\n\nexport async function cmdSpotGet(\n client: OkxRestClient,\n opts: { instId: string; ordId?: string; clOrdId?: string; json: boolean },\n): Promise<void> {\n const params: Record<string, unknown> = { instId: opts.instId };\n if (opts.ordId) params[\"ordId\"] = opts.ordId;\n if (opts.clOrdId) params[\"clOrdId\"] = opts.clOrdId;\n const res = await client.privateGet(\"/api/v5/trade/order\", params);\n const data = res.data as Record<string, unknown>[];\n if (opts.json) return printJson(data);\n const o = data?.[0];\n if (!o) { process.stdout.write(\"No data\\n\"); return; }\n printKv({\n ordId: o[\"ordId\"],\n instId: o[\"instId\"],\n side: o[\"side\"],\n ordType: o[\"ordType\"],\n px: o[\"px\"],\n sz: o[\"sz\"],\n fillSz: o[\"fillSz\"],\n avgPx: o[\"avgPx\"],\n state: o[\"state\"],\n cTime: new Date(Number(o[\"cTime\"])).toLocaleString(),\n });\n}\n\nexport async function cmdSpotAmend(\n client: OkxRestClient,\n opts: {\n instId: string;\n ordId?: string;\n clOrdId?: string;\n newSz?: string;\n newPx?: string;\n json: boolean;\n },\n): Promise<void> {\n const body: Record<string, unknown> = { instId: opts.instId };\n if (opts.ordId) body[\"ordId\"] = opts.ordId;\n if (opts.clOrdId) body[\"clOrdId\"] = opts.clOrdId;\n if (opts.newSz) body[\"newSz\"] = opts.newSz;\n if (opts.newPx) body[\"newPx\"] = opts.newPx;\n const res = await client.privatePost(\"/api/v5/trade/amend-order\", body);\n if (opts.json) return printJson(res.data);\n const r = (res.data as Record<string, unknown>[])[0];\n process.stdout.write(`Order amended: ${r?.[\"ordId\"]} (${r?.[\"sCode\"] === \"0\" ? \"OK\" : r?.[\"sMsg\"]})\\n`);\n}\n\nexport async function cmdSpotAlgoOrders(\n client: OkxRestClient,\n opts: { instId?: string; status: \"pending\" | \"history\"; ordType?: string; json: boolean },\n): Promise<void> {\n const endpoint =\n opts.status === \"history\"\n ? \"/api/v5/trade/orders-algo-history\"\n : \"/api/v5/trade/orders-algo-pending\";\n const baseParams: Record<string, unknown> = { instType: \"SPOT\" };\n if (opts.instId) baseParams[\"instId\"] = opts.instId;\n\n let orders: Record<string, unknown>[];\n if (opts.ordType) {\n const res = await client.privateGet(endpoint, { ...baseParams, ordType: opts.ordType });\n orders = (res.data as Record<string, unknown>[]) ?? [];\n } else {\n const [r1, r2] = await Promise.all([\n client.privateGet(endpoint, { ...baseParams, ordType: \"conditional\" }),\n client.privateGet(endpoint, { ...baseParams, ordType: \"oco\" }),\n ]);\n orders = [\n ...((r1.data as Record<string, unknown>[]) ?? []),\n ...((r2.data as Record<string, unknown>[]) ?? []),\n ];\n }\n\n if (opts.json) return printJson(orders);\n if (!(orders ?? []).length) { process.stdout.write(\"No algo orders\\n\"); return; }\n printTable(\n orders.map((o) => ({\n algoId: o[\"algoId\"],\n instId: o[\"instId\"],\n type: o[\"ordType\"],\n side: o[\"side\"],\n sz: o[\"sz\"],\n tpTrigger: o[\"tpTriggerPx\"],\n slTrigger: o[\"slTriggerPx\"],\n state: o[\"state\"],\n })),\n );\n}\n\nexport async function cmdSpotFills(\n client: OkxRestClient,\n opts: { instId?: string; ordId?: string; json: boolean },\n): Promise<void> {\n const params: Record<string, unknown> = { instType: \"SPOT\" };\n if (opts.instId) params[\"instId\"] = opts.instId;\n if (opts.ordId) params[\"ordId\"] = opts.ordId;\n const res = await client.privateGet(\"/api/v5/trade/fills\", params);\n const fills = res.data as Record<string, unknown>[];\n if (opts.json) return printJson(fills);\n printTable(\n (fills ?? []).map((f) => ({\n instId: f[\"instId\"],\n side: f[\"side\"],\n fillPx: f[\"fillPx\"],\n fillSz: f[\"fillSz\"],\n fee: f[\"fee\"],\n ts: new Date(Number(f[\"ts\"])).toLocaleString(),\n })),\n );\n}\n","import type { OkxRestClient } from \"@okx-hub/core\";\nimport { printJson, printKv, printTable } from \"../formatter.js\";\n\nexport async function cmdSwapPositions(\n client: OkxRestClient,\n instId: string | undefined,\n json: boolean,\n): Promise<void> {\n const params: Record<string, unknown> = { instType: \"SWAP\" };\n if (instId) params[\"instId\"] = instId;\n const res = await client.privateGet(\"/api/v5/account/positions\", params);\n const positions = res.data as Record<string, unknown>[];\n if (json) return printJson(positions);\n const open = (positions ?? []).filter((p) => Number(p[\"pos\"]) !== 0);\n if (!open.length) { process.stdout.write(\"No open positions\\n\"); return; }\n printTable(\n open.map((p) => ({\n instId: p[\"instId\"],\n side: p[\"posSide\"],\n size: p[\"pos\"],\n avgPx: p[\"avgPx\"],\n upl: p[\"upl\"],\n uplRatio: p[\"uplRatio\"],\n lever: p[\"lever\"],\n })),\n );\n}\n\nexport async function cmdSwapOrders(\n client: OkxRestClient,\n opts: { instId?: string; status: \"open\" | \"history\"; json: boolean },\n): Promise<void> {\n const endpoint =\n opts.status === \"history\"\n ? \"/api/v5/trade/orders-history\"\n : \"/api/v5/trade/orders-pending\";\n const params: Record<string, unknown> = { instType: \"SWAP\" };\n if (opts.instId) params[\"instId\"] = opts.instId;\n const res = await client.privateGet(endpoint, params);\n const orders = res.data as Record<string, unknown>[];\n if (opts.json) return printJson(orders);\n printTable(\n (orders ?? []).map((o) => ({\n ordId: o[\"ordId\"],\n instId: o[\"instId\"],\n side: o[\"side\"],\n posSide: o[\"posSide\"],\n type: o[\"ordType\"],\n price: o[\"px\"],\n size: o[\"sz\"],\n state: o[\"state\"],\n })),\n );\n}\n\nexport async function cmdSwapPlace(\n client: OkxRestClient,\n opts: {\n instId: string;\n side: string;\n ordType: string;\n sz: string;\n posSide?: string;\n px?: string;\n tdMode: string;\n json: boolean;\n },\n): Promise<void> {\n const body: Record<string, unknown> = {\n instId: opts.instId,\n tdMode: opts.tdMode,\n side: opts.side,\n ordType: opts.ordType,\n sz: opts.sz,\n };\n if (opts.posSide) body[\"posSide\"] = opts.posSide;\n if (opts.px) body[\"px\"] = opts.px;\n const res = await client.privatePost(\"/api/v5/trade/order\", body);\n if (opts.json) return printJson(res.data);\n const order = (res.data as Record<string, unknown>[])[0];\n process.stdout.write(`Order placed: ${order?.[\"ordId\"]} (${order?.[\"sCode\"] === \"0\" ? \"OK\" : order?.[\"sMsg\"]})\\n`);\n}\n\nexport async function cmdSwapCancel(\n client: OkxRestClient,\n instId: string,\n ordId: string,\n json: boolean,\n): Promise<void> {\n const res = await client.privatePost(\"/api/v5/trade/cancel-order\", { instId, ordId });\n if (json) return printJson(res.data);\n const r = (res.data as Record<string, unknown>[])[0];\n process.stdout.write(`Cancelled: ${r?.[\"ordId\"]} (${r?.[\"sCode\"] === \"0\" ? \"OK\" : r?.[\"sMsg\"]})\\n`);\n}\n\nexport async function cmdSwapAlgoPlace(\n client: OkxRestClient,\n opts: {\n instId: string;\n side: string;\n ordType: string;\n sz: string;\n posSide?: string;\n tdMode: string;\n tpTriggerPx?: string;\n tpOrdPx?: string;\n slTriggerPx?: string;\n slOrdPx?: string;\n reduceOnly?: boolean;\n json: boolean;\n },\n): Promise<void> {\n const body: Record<string, unknown> = {\n instId: opts.instId,\n tdMode: opts.tdMode,\n side: opts.side,\n ordType: opts.ordType,\n sz: opts.sz,\n };\n if (opts.posSide) body[\"posSide\"] = opts.posSide;\n if (opts.tpTriggerPx) body[\"tpTriggerPx\"] = opts.tpTriggerPx;\n if (opts.tpOrdPx) body[\"tpOrdPx\"] = opts.tpOrdPx;\n if (opts.slTriggerPx) body[\"slTriggerPx\"] = opts.slTriggerPx;\n if (opts.slOrdPx) body[\"slOrdPx\"] = opts.slOrdPx;\n if (opts.reduceOnly !== undefined) body[\"reduceOnly\"] = String(opts.reduceOnly);\n const res = await client.privatePost(\"/api/v5/trade/order-algo\", body);\n if (opts.json) return printJson(res.data);\n const order = (res.data as Record<string, unknown>[])[0];\n process.stdout.write(\n `Algo order placed: ${order?.[\"algoId\"]} (${order?.[\"sCode\"] === \"0\" ? \"OK\" : order?.[\"sMsg\"]})\\n`,\n );\n}\n\nexport async function cmdSwapAlgoAmend(\n client: OkxRestClient,\n opts: {\n instId: string;\n algoId: string;\n newSz?: string;\n newTpTriggerPx?: string;\n newTpOrdPx?: string;\n newSlTriggerPx?: string;\n newSlOrdPx?: string;\n json: boolean;\n },\n): Promise<void> {\n const body: Record<string, unknown> = {\n instId: opts.instId,\n algoId: opts.algoId,\n };\n if (opts.newSz) body[\"newSz\"] = opts.newSz;\n if (opts.newTpTriggerPx) body[\"newTpTriggerPx\"] = opts.newTpTriggerPx;\n if (opts.newTpOrdPx) body[\"newTpOrdPx\"] = opts.newTpOrdPx;\n if (opts.newSlTriggerPx) body[\"newSlTriggerPx\"] = opts.newSlTriggerPx;\n if (opts.newSlOrdPx) body[\"newSlOrdPx\"] = opts.newSlOrdPx;\n const res = await client.privatePost(\"/api/v5/trade/amend-algos\", body);\n if (opts.json) return printJson(res.data);\n const r = (res.data as Record<string, unknown>[])[0];\n process.stdout.write(\n `Algo order amended: ${r?.[\"algoId\"]} (${r?.[\"sCode\"] === \"0\" ? \"OK\" : r?.[\"sMsg\"]})\\n`,\n );\n}\n\nexport async function cmdSwapAlgoTrailPlace(\n client: OkxRestClient,\n opts: {\n instId: string;\n side: string;\n sz: string;\n callbackRatio?: string;\n callbackSpread?: string;\n activePx?: string;\n posSide?: string;\n tdMode: string;\n reduceOnly?: boolean;\n json: boolean;\n },\n): Promise<void> {\n const body: Record<string, unknown> = {\n instId: opts.instId,\n tdMode: opts.tdMode,\n side: opts.side,\n ordType: \"move_order_stop\",\n sz: opts.sz,\n };\n if (opts.posSide) body[\"posSide\"] = opts.posSide;\n if (opts.callbackRatio) body[\"callbackRatio\"] = opts.callbackRatio;\n if (opts.callbackSpread) body[\"callbackSpread\"] = opts.callbackSpread;\n if (opts.activePx) body[\"activePx\"] = opts.activePx;\n if (opts.reduceOnly !== undefined) body[\"reduceOnly\"] = String(opts.reduceOnly);\n const res = await client.privatePost(\"/api/v5/trade/order-algo\", body);\n if (opts.json) return printJson(res.data);\n const order = (res.data as Record<string, unknown>[])[0];\n process.stdout.write(\n `Trailing stop placed: ${order?.[\"algoId\"]} (${order?.[\"sCode\"] === \"0\" ? \"OK\" : order?.[\"sMsg\"]})\\n`,\n );\n}\n\nexport async function cmdSwapAlgoCancel(\n client: OkxRestClient,\n instId: string,\n algoId: string,\n json: boolean,\n): Promise<void> {\n const res = await client.privatePost(\"/api/v5/trade/cancel-algos\", [\n { algoId, instId },\n ]);\n if (json) return printJson(res.data);\n const r = (res.data as Record<string, unknown>[])[0];\n process.stdout.write(\n `Algo order cancelled: ${r?.[\"algoId\"]} (${r?.[\"sCode\"] === \"0\" ? \"OK\" : r?.[\"sMsg\"]})\\n`,\n );\n}\n\nexport async function cmdSwapAlgoOrders(\n client: OkxRestClient,\n opts: { instId?: string; status: \"pending\" | \"history\"; ordType?: string; json: boolean },\n): Promise<void> {\n const endpoint =\n opts.status === \"history\"\n ? \"/api/v5/trade/orders-algo-history\"\n : \"/api/v5/trade/orders-algo-pending\";\n const baseParams: Record<string, unknown> = { instType: \"SWAP\" };\n if (opts.instId) baseParams[\"instId\"] = opts.instId;\n\n let orders: Record<string, unknown>[];\n if (opts.ordType) {\n const res = await client.privateGet(endpoint, { ...baseParams, ordType: opts.ordType });\n orders = (res.data as Record<string, unknown>[]) ?? [];\n } else {\n const [r1, r2, r3] = await Promise.all([\n client.privateGet(endpoint, { ...baseParams, ordType: \"conditional\" }),\n client.privateGet(endpoint, { ...baseParams, ordType: \"oco\" }),\n client.privateGet(endpoint, { ...baseParams, ordType: \"move_order_stop\" }),\n ]);\n orders = [\n ...((r1.data as Record<string, unknown>[]) ?? []),\n ...((r2.data as Record<string, unknown>[]) ?? []),\n ...((r3.data as Record<string, unknown>[]) ?? []),\n ];\n }\n\n if (opts.json) return printJson(orders);\n if (!(orders ?? []).length) { process.stdout.write(\"No algo orders\\n\"); return; }\n printTable(\n orders.map((o) => ({\n algoId: o[\"algoId\"],\n instId: o[\"instId\"],\n type: o[\"ordType\"],\n side: o[\"side\"],\n sz: o[\"sz\"],\n tpTrigger: o[\"tpTriggerPx\"],\n slTrigger: o[\"slTriggerPx\"],\n state: o[\"state\"],\n })),\n );\n}\n\nexport async function cmdSwapFills(\n client: OkxRestClient,\n opts: { instId?: string; ordId?: string; archive: boolean; json: boolean },\n): Promise<void> {\n const path = opts.archive ? \"/api/v5/trade/fills-history\" : \"/api/v5/trade/fills\";\n const params: Record<string, unknown> = { instType: \"SWAP\" };\n if (opts.instId) params[\"instId\"] = opts.instId;\n if (opts.ordId) params[\"ordId\"] = opts.ordId;\n const res = await client.privateGet(path, params);\n const fills = res.data as Record<string, unknown>[];\n if (opts.json) return printJson(fills);\n printTable(\n (fills ?? []).map((f) => ({\n instId: f[\"instId\"],\n side: f[\"side\"],\n fillPx: f[\"fillPx\"],\n fillSz: f[\"fillSz\"],\n fee: f[\"fee\"],\n ts: new Date(Number(f[\"ts\"])).toLocaleString(),\n })),\n );\n}\n\nexport async function cmdSwapGet(\n client: OkxRestClient,\n opts: { instId: string; ordId?: string; clOrdId?: string; json: boolean },\n): Promise<void> {\n const params: Record<string, unknown> = { instId: opts.instId };\n if (opts.ordId) params[\"ordId\"] = opts.ordId;\n if (opts.clOrdId) params[\"clOrdId\"] = opts.clOrdId;\n const res = await client.privateGet(\"/api/v5/trade/order\", params);\n const data = res.data as Record<string, unknown>[];\n if (opts.json) return printJson(data);\n const o = data?.[0];\n if (!o) { process.stdout.write(\"No data\\n\"); return; }\n printKv({\n ordId: o[\"ordId\"],\n instId: o[\"instId\"],\n side: o[\"side\"],\n posSide: o[\"posSide\"],\n ordType: o[\"ordType\"],\n px: o[\"px\"],\n sz: o[\"sz\"],\n fillSz: o[\"fillSz\"],\n avgPx: o[\"avgPx\"],\n state: o[\"state\"],\n cTime: new Date(Number(o[\"cTime\"])).toLocaleString(),\n });\n}\n\nexport async function cmdSwapClose(\n client: OkxRestClient,\n opts: { instId: string; mgnMode: string; posSide?: string; autoCxl?: boolean; json: boolean },\n): Promise<void> {\n const body: Record<string, unknown> = {\n instId: opts.instId,\n mgnMode: opts.mgnMode,\n };\n if (opts.posSide) body[\"posSide\"] = opts.posSide;\n if (opts.autoCxl !== undefined) body[\"autoCxl\"] = String(opts.autoCxl);\n const res = await client.privatePost(\"/api/v5/trade/close-position\", body);\n if (opts.json) return printJson(res.data);\n const r = (res.data as Record<string, unknown>[])[0];\n process.stdout.write(`Position closed: ${r?.[\"instId\"]} ${r?.[\"posSide\"] ?? \"\"}\\n`);\n}\n\nexport async function cmdSwapGetLeverage(\n client: OkxRestClient,\n opts: { instId: string; mgnMode: string; json: boolean },\n): Promise<void> {\n const res = await client.privateGet(\"/api/v5/account/leverage-info\", {\n instId: opts.instId,\n mgnMode: opts.mgnMode,\n });\n const data = res.data as Record<string, unknown>[];\n if (opts.json) return printJson(data);\n printTable(\n (data ?? []).map((r) => ({\n instId: r[\"instId\"],\n mgnMode: r[\"mgnMode\"],\n posSide: r[\"posSide\"],\n lever: r[\"lever\"],\n })),\n );\n}\n\nexport async function cmdSwapSetLeverage(\n client: OkxRestClient,\n opts: { instId: string; lever: string; mgnMode: string; posSide?: string; json: boolean },\n): Promise<void> {\n const body: Record<string, unknown> = {\n instId: opts.instId,\n lever: opts.lever,\n mgnMode: opts.mgnMode,\n };\n if (opts.posSide) body[\"posSide\"] = opts.posSide;\n const res = await client.privatePost(\"/api/v5/account/set-leverage\", body);\n if (opts.json) return printJson(res.data);\n const r = (res.data as Record<string, unknown>[])[0];\n process.stdout.write(`Leverage set: ${r?.[\"lever\"]}x ${r?.[\"instId\"]}\\n`);\n}\n","import type { OkxRestClient } from \"@okx-hub/core\";\nimport { printJson, printKv, printTable } from \"../formatter.js\";\n\nexport async function cmdFuturesOrders(\n client: OkxRestClient,\n opts: { instId?: string; status: \"open\" | \"history\" | \"archive\"; json: boolean },\n): Promise<void> {\n const path =\n opts.status === \"archive\"\n ? \"/api/v5/trade/orders-history-archive\"\n : opts.status === \"history\"\n ? \"/api/v5/trade/orders-history\"\n : \"/api/v5/trade/orders-pending\";\n const params: Record<string, unknown> = { instType: \"FUTURES\" };\n if (opts.instId) params[\"instId\"] = opts.instId;\n const res = await client.privateGet(path, params);\n const orders = res.data as Record<string, unknown>[];\n if (opts.json) return printJson(orders);\n printTable(\n (orders ?? []).map((o) => ({\n ordId: o[\"ordId\"],\n instId: o[\"instId\"],\n side: o[\"side\"],\n posSide: o[\"posSide\"],\n type: o[\"ordType\"],\n price: o[\"px\"],\n size: o[\"sz\"],\n state: o[\"state\"],\n })),\n );\n}\n\nexport async function cmdFuturesPositions(\n client: OkxRestClient,\n instId: string | undefined,\n json: boolean,\n): Promise<void> {\n const params: Record<string, unknown> = { instType: \"FUTURES\" };\n if (instId) params[\"instId\"] = instId;\n const res = await client.privateGet(\"/api/v5/account/positions\", params);\n const positions = res.data as Record<string, unknown>[];\n if (json) return printJson(positions);\n const open = (positions ?? []).filter((p) => Number(p[\"pos\"]) !== 0);\n if (!open.length) { process.stdout.write(\"No open positions\\n\"); return; }\n printTable(\n open.map((p) => ({\n instId: p[\"instId\"],\n side: p[\"posSide\"],\n pos: p[\"pos\"],\n avgPx: p[\"avgPx\"],\n upl: p[\"upl\"],\n lever: p[\"lever\"],\n })),\n );\n}\n\nexport async function cmdFuturesFills(\n client: OkxRestClient,\n opts: { instId?: string; ordId?: string; archive: boolean; json: boolean },\n): Promise<void> {\n const path = opts.archive ? \"/api/v5/trade/fills-history\" : \"/api/v5/trade/fills\";\n const params: Record<string, unknown> = { instType: \"FUTURES\" };\n if (opts.instId) params[\"instId\"] = opts.instId;\n if (opts.ordId) params[\"ordId\"] = opts.ordId;\n const res = await client.privateGet(path, params);\n const fills = res.data as Record<string, unknown>[];\n if (opts.json) return printJson(fills);\n printTable(\n (fills ?? []).map((f) => ({\n instId: f[\"instId\"],\n side: f[\"side\"],\n fillPx: f[\"fillPx\"],\n fillSz: f[\"fillSz\"],\n fee: f[\"fee\"],\n ts: new Date(Number(f[\"ts\"])).toLocaleString(),\n })),\n );\n}\n\nexport async function cmdFuturesPlace(\n client: OkxRestClient,\n opts: {\n instId: string;\n side: string;\n ordType: string;\n sz: string;\n tdMode: string;\n posSide?: string;\n px?: string;\n reduceOnly?: boolean;\n json: boolean;\n },\n): Promise<void> {\n const body: Record<string, unknown> = {\n instId: opts.instId,\n tdMode: opts.tdMode,\n side: opts.side,\n ordType: opts.ordType,\n sz: opts.sz,\n };\n if (opts.posSide) body[\"posSide\"] = opts.posSide;\n if (opts.px) body[\"px\"] = opts.px;\n if (opts.reduceOnly !== undefined) body[\"reduceOnly\"] = String(opts.reduceOnly);\n const res = await client.privatePost(\"/api/v5/trade/order\", body);\n if (opts.json) return printJson(res.data);\n const order = (res.data as Record<string, unknown>[])[0];\n process.stdout.write(`Order placed: ${order?.[\"ordId\"]} (${order?.[\"sCode\"] === \"0\" ? \"OK\" : order?.[\"sMsg\"]})\\n`);\n}\n\nexport async function cmdFuturesCancel(\n client: OkxRestClient,\n instId: string,\n ordId: string,\n json: boolean,\n): Promise<void> {\n const res = await client.privatePost(\"/api/v5/trade/cancel-order\", { instId, ordId });\n if (json) return printJson(res.data);\n const r = (res.data as Record<string, unknown>[])[0];\n process.stdout.write(`Cancelled: ${r?.[\"ordId\"]} (${r?.[\"sCode\"] === \"0\" ? \"OK\" : r?.[\"sMsg\"]})\\n`);\n}\n\nexport async function cmdFuturesGet(\n client: OkxRestClient,\n opts: { instId: string; ordId?: string; json: boolean },\n): Promise<void> {\n const params: Record<string, unknown> = { instId: opts.instId };\n if (opts.ordId) params[\"ordId\"] = opts.ordId;\n const res = await client.privateGet(\"/api/v5/trade/order\", params);\n const data = res.data as Record<string, unknown>[];\n if (opts.json) return printJson(data);\n const o = data?.[0];\n if (!o) { process.stdout.write(\"No data\\n\"); return; }\n printKv({\n ordId: o[\"ordId\"],\n instId: o[\"instId\"],\n side: o[\"side\"],\n posSide: o[\"posSide\"],\n ordType: o[\"ordType\"],\n px: o[\"px\"],\n sz: o[\"sz\"],\n fillSz: o[\"fillSz\"],\n avgPx: o[\"avgPx\"],\n state: o[\"state\"],\n cTime: new Date(Number(o[\"cTime\"])).toLocaleString(),\n });\n}\n","import { writeFileSync, mkdirSync, existsSync } from \"node:fs\";\nimport { stringify } from \"smol-toml\";\nimport { configFilePath } from \"@okx-hub/core\";\nimport type { OkxTomlConfig } from \"@okx-hub/core\";\n\n// Re-export for backward compat within CLI\nexport type { OkxTomlConfig as CliConfig };\nexport { configFilePath as configPath };\n\nexport function configDir(): string {\n return configFilePath().replace(/\\/config\\.toml$/, \"\");\n}\n\nexport function writeCliConfig(config: OkxTomlConfig): void {\n const dir = configDir();\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n writeFileSync(configFilePath(), stringify(config as unknown as Record<string, unknown>), \"utf-8\");\n}\n","import { readTomlProfile, configFilePath } from \"@okx-hub/core\";\nimport { writeCliConfig } from \"../config/toml.js\";\nimport { printJson, printKv } from \"../formatter.js\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { parse, stringify } from \"smol-toml\";\nimport type { OkxTomlConfig } from \"@okx-hub/core\";\nimport { createInterface } from \"node:readline\";\nimport { spawnSync } from \"node:child_process\";\n\nfunction readFullConfig(): OkxTomlConfig {\n const path = configFilePath();\n if (!existsSync(path)) return { profiles: {} };\n const raw = readFileSync(path, \"utf-8\");\n return parse(raw) as unknown as OkxTomlConfig;\n}\n\nfunction prompt(rl: ReturnType<typeof createInterface>, question: string): Promise<string> {\n return new Promise((resolve) => rl.question(question, resolve));\n}\n\nexport function cmdConfigShow(json: boolean): void {\n const config = readFullConfig();\n if (json) return printJson(config);\n process.stdout.write(`Config: ${configFilePath()}\\n\\n`);\n process.stdout.write(`default_profile: ${config.default_profile ?? \"(not set)\"}\\n\\n`);\n for (const [name, profile] of Object.entries(config.profiles)) {\n process.stdout.write(`[${name}]\\n`);\n printKv({\n api_key: profile.api_key ? \"***\" + profile.api_key.slice(-4) : \"(not set)\",\n demo: profile.demo ?? false,\n base_url: profile.base_url ?? \"(default)\",\n }, 2);\n process.stdout.write(\"\\n\");\n }\n}\n\nexport function cmdConfigSet(key: string, value: string): void {\n const config = readFullConfig();\n if (key === \"default_profile\") {\n config.default_profile = value;\n writeCliConfig(config);\n process.stdout.write(`default_profile set to \"${value}\"\\n`);\n } else {\n process.stderr.write(`Unknown config key: ${key}\\n`);\n process.exitCode = 1;\n }\n}\n\nexport async function cmdConfigInit(): Promise<void> {\n const apiUrl = \"https://www.okx.com/account/my-api\";\n\n process.stdout.write(\"OKX Trade CLI — 配置向导\\n\\n\");\n process.stdout.write(`请前往 ${apiUrl} 创建 API Key(需要 trade 权限)\\n\\n`);\n\n // Try to open the URL; silently ignore failures\n try {\n const opener = process.platform === \"darwin\" ? \"open\" : \"xdg-open\";\n spawnSync(opener, [apiUrl], { stdio: \"ignore\" });\n } catch {\n // silently ignore\n }\n\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n\n try {\n const profileNameRaw = await prompt(rl, \"Profile 名称 (默认: default): \");\n const profileName = profileNameRaw.trim() || \"default\";\n\n const apiKey = (await prompt(rl, \"API Key: \")).trim();\n if (!apiKey) {\n process.stderr.write(\"错误: API Key 不能为空\\n\");\n process.exitCode = 1;\n return;\n }\n\n const secretKey = (await prompt(rl, \"Secret Key: \")).trim();\n if (!secretKey) {\n process.stderr.write(\"错误: Secret Key 不能为空\\n\");\n process.exitCode = 1;\n return;\n }\n\n const passphrase = (await prompt(rl, \"Passphrase: \")).trim();\n if (!passphrase) {\n process.stderr.write(\"错误: Passphrase 不能为空\\n\");\n process.exitCode = 1;\n return;\n }\n\n const demoRaw = (await prompt(rl, \"使用模拟盘?(Y/n) \")).trim().toLowerCase();\n const demo = demoRaw !== \"n\";\n if (demo) {\n process.stdout.write(\"已选择模拟盘模式,可随时通过 okx config set 切换为实盘。\\n\");\n }\n\n const config = readFullConfig();\n config.profiles[profileName] = { api_key: apiKey, secret_key: secretKey, passphrase, demo };\n\n const configPath = configFilePath();\n try {\n writeCliConfig(config);\n process.stdout.write(`\\n配置已保存到 ${configPath}\\n`);\n process.stdout.write(`使用方式: okx --profile ${profileName} account balance\\n`);\n if (!config.default_profile) {\n process.stdout.write(`提示: 运行 okx config set default_profile ${profileName} 可将其设为默认\\n`);\n }\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n const isPermission = err instanceof Error && \"code\" in err && (err.code === \"EACCES\" || err.code === \"EPERM\");\n process.stderr.write(`写入配置文件失败: ${message}\\n`);\n if (isPermission) {\n process.stderr.write(`权限不足,请检查 ${configPath} 及其父目录的读写权限。\\n`);\n }\n process.stderr.write(\"请手动将以下内容写入 \" + configPath + \":\\n\\n\");\n process.stdout.write(stringify(config as unknown as Record<string, unknown>) + \"\\n\");\n process.exitCode = 1;\n }\n } finally {\n rl.close();\n }\n}\n","import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport * as os from \"node:os\";\nimport * as readline from \"node:readline\";\n\ninterface ClientConfig {\n name: string;\n configPath: string;\n mcpKey: string;\n}\n\nconst CLIENTS: ClientConfig[] = [\n {\n name: \"Claude Desktop\",\n configPath: path.join(os.homedir(), \"Library/Application Support/Claude/claude_desktop_config.json\"),\n mcpKey: \"mcpServers\",\n },\n {\n name: \"Cursor\",\n configPath: path.join(os.homedir(), \".cursor/mcp.json\"),\n mcpKey: \"mcpServers\",\n },\n {\n name: \"Windsurf\",\n configPath: path.join(os.homedir(), \".codeium/windsurf/mcp_config.json\"),\n mcpKey: \"mcpServers\",\n },\n];\n\nconst MCP_ENTRY = {\n command: \"okx-trade-mcp\",\n args: [\"--modules\", \"all\"],\n};\n\nconst MCP_SERVER_NAME = \"okx-trade-mcp\";\n\nfunction prompt(rl: readline.Interface, question: string): Promise<string> {\n return new Promise((resolve) => {\n rl.question(question, (answer) => {\n resolve(answer);\n });\n });\n}\n\nexport async function cmdSetupClients(): Promise<void> {\n const detected = CLIENTS.filter((c) => fs.existsSync(c.configPath));\n\n if (detected.length === 0) {\n process.stdout.write(\n \"No supported IDE/client installations detected.\\n\" +\n \"Checked:\\n\" +\n CLIENTS.map((c) => ` - ${c.name}: ${c.configPath}`).join(\"\\n\") +\n \"\\n\"\n );\n return;\n }\n\n process.stdout.write(`Detected ${detected.length} client(s):\\n`);\n for (const c of detected) {\n process.stdout.write(` - ${c.name}\\n`);\n }\n process.stdout.write(\"\\n\");\n\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n try {\n for (const client of detected) {\n const answer = await prompt(rl, `Configure ${client.name}? (y/N) `);\n if (answer.trim().toLowerCase() !== \"y\") {\n process.stdout.write(` Skipped ${client.name}.\\n`);\n continue;\n }\n\n // Read existing config or initialize a new one\n let data: Record<string, unknown> = { [client.mcpKey]: {} };\n if (fs.existsSync(client.configPath)) {\n const raw = fs.readFileSync(client.configPath, \"utf-8\");\n try {\n data = JSON.parse(raw) as Record<string, unknown>;\n } catch {\n process.stderr.write(\n ` Error: Failed to parse JSON for ${client.name} at ${client.configPath}. Skipping.\\n`\n );\n continue;\n }\n }\n\n // Ensure the mcpKey object exists\n if (typeof data[client.mcpKey] !== \"object\" || data[client.mcpKey] === null) {\n data[client.mcpKey] = {};\n }\n\n const servers = data[client.mcpKey] as Record<string, unknown>;\n\n if (Object.prototype.hasOwnProperty.call(servers, MCP_SERVER_NAME)) {\n process.stdout.write(` Already configured in ${client.name}. Skipping.\\n`);\n continue;\n }\n\n servers[MCP_SERVER_NAME] = MCP_ENTRY;\n\n const jsonOutput = JSON.stringify(data, null, 2);\n\n try {\n fs.writeFileSync(client.configPath, jsonOutput, \"utf-8\");\n process.stdout.write(` Configured ${client.name} successfully.\\n`);\n } catch (err) {\n const reason = err instanceof Error ? err.message : String(err);\n process.stderr.write(\n ` Error: Failed to write config for ${client.name}: ${reason}\\n` +\n ` Add the following to \"${client.configPath}\" manually:\\n\\n` +\n ` \"${MCP_SERVER_NAME}\": ${JSON.stringify(MCP_ENTRY, null, 2)\n .split(\"\\n\")\n .join(\"\\n \")}\\n\\n`\n );\n }\n }\n } finally {\n rl.close();\n }\n\n process.stdout.write(\n \"\\nDone. Please restart any configured IDE/client for the changes to take effect.\\n\"\n );\n}\n","import type { OkxRestClient } from \"@okx-hub/core\";\nimport { printJson, printTable, printKv } from \"../formatter.js\";\n\n// ─── grid orders ─────────────────────────────────────────────────────────────\n\nexport async function cmdGridOrders(\n client: OkxRestClient,\n opts: {\n algoOrdType: string;\n instId?: string;\n algoId?: string;\n status: \"active\" | \"history\";\n json: boolean;\n },\n): Promise<void> {\n const path =\n opts.status === \"history\"\n ? \"/api/v5/tradingBot/grid/orders-algo-history\"\n : \"/api/v5/tradingBot/grid/orders-algo-pending\";\n const params: Record<string, unknown> = { algoOrdType: opts.algoOrdType };\n if (opts.instId) params[\"instId\"] = opts.instId;\n if (opts.algoId) params[\"algoId\"] = opts.algoId;\n const res = await client.privateGet(path, params);\n const orders = (res.data as Record<string, unknown>[]) ?? [];\n if (opts.json) return printJson(orders);\n if (!orders.length) { process.stdout.write(\"No grid bots\\n\"); return; }\n printTable(\n orders.map((o) => ({\n algoId: o[\"algoId\"],\n instId: o[\"instId\"],\n type: o[\"algoOrdType\"],\n state: o[\"state\"],\n pnl: o[\"pnlRatio\"],\n gridNum: o[\"gridNum\"],\n maxPx: o[\"maxPx\"],\n minPx: o[\"minPx\"],\n createdAt: new Date(Number(o[\"cTime\"])).toLocaleString(),\n })),\n );\n}\n\n// ─── grid details ─────────────────────────────────────────────────────────────\n\nexport async function cmdGridDetails(\n client: OkxRestClient,\n opts: { algoOrdType: string; algoId: string; json: boolean },\n): Promise<void> {\n const res = await client.privateGet(\"/api/v5/tradingBot/grid/orders-algo-details\", {\n algoOrdType: opts.algoOrdType,\n algoId: opts.algoId,\n });\n const detail = ((res.data as Record<string, unknown>[]) ?? [])[0];\n if (!detail) { process.stdout.write(\"Bot not found\\n\"); return; }\n if (opts.json) return printJson(detail);\n printKv({\n algoId: detail[\"algoId\"],\n instId: detail[\"instId\"],\n type: detail[\"algoOrdType\"],\n state: detail[\"state\"],\n maxPx: detail[\"maxPx\"],\n minPx: detail[\"minPx\"],\n gridNum: detail[\"gridNum\"],\n runType: detail[\"runType\"] === \"1\" ? \"arithmetic\" : \"geometric\",\n pnl: detail[\"pnl\"],\n pnlRatio: detail[\"pnlRatio\"],\n investAmt: detail[\"investAmt\"],\n totalAnnRate: detail[\"totalAnnRate\"],\n createdAt: new Date(Number(detail[\"cTime\"])).toLocaleString(),\n });\n}\n\n// ─── grid sub-orders ──────────────────────────────────────────────────────────\n\nexport async function cmdGridSubOrders(\n client: OkxRestClient,\n opts: {\n algoOrdType: string;\n algoId: string;\n type: \"filled\" | \"live\";\n json: boolean;\n },\n): Promise<void> {\n const res = await client.privateGet(\"/api/v5/tradingBot/grid/sub-orders\", {\n algoOrdType: opts.algoOrdType,\n algoId: opts.algoId,\n type: opts.type,\n });\n const orders = (res.data as Record<string, unknown>[]) ?? [];\n if (opts.json) return printJson(orders);\n if (!orders.length) { process.stdout.write(\"No sub-orders\\n\"); return; }\n printTable(\n orders.map((o) => ({\n ordId: o[\"ordId\"],\n side: o[\"side\"],\n px: o[\"px\"],\n sz: o[\"sz\"],\n fillPx: o[\"fillPx\"],\n fillSz: o[\"fillSz\"],\n state: o[\"state\"],\n fee: o[\"fee\"],\n })),\n );\n}\n\n// ─── grid create ──────────────────────────────────────────────────────────────\n\nexport async function cmdGridCreate(\n client: OkxRestClient,\n opts: {\n instId: string;\n algoOrdType: string;\n maxPx: string;\n minPx: string;\n gridNum: string;\n runType?: string;\n quoteSz?: string;\n baseSz?: string;\n direction?: string;\n lever?: string;\n sz?: string;\n json: boolean;\n },\n): Promise<void> {\n const body: Record<string, unknown> = {\n instId: opts.instId,\n algoOrdType: opts.algoOrdType,\n maxPx: opts.maxPx,\n minPx: opts.minPx,\n gridNum: opts.gridNum,\n };\n if (opts.runType) body[\"runType\"] = opts.runType;\n if (opts.quoteSz) body[\"quoteSz\"] = opts.quoteSz;\n if (opts.baseSz) body[\"baseSz\"] = opts.baseSz;\n if (opts.direction) body[\"direction\"] = opts.direction;\n if (opts.lever) body[\"lever\"] = opts.lever;\n if (opts.sz) body[\"sz\"] = opts.sz;\n const res = await client.privatePost(\"/api/v5/tradingBot/grid/order-algo\", body);\n if (opts.json) return printJson(res.data);\n const r = (res.data as Record<string, unknown>[])[0];\n process.stdout.write(\n `Grid bot created: ${r?.[\"algoId\"]} (${r?.[\"sCode\"] === \"0\" ? \"OK\" : r?.[\"sMsg\"]})\\n`,\n );\n}\n\n// ─── grid stop ────────────────────────────────────────────────────────────────\n\nexport async function cmdGridStop(\n client: OkxRestClient,\n opts: {\n algoId: string;\n algoOrdType: string;\n instId: string;\n stopType?: string;\n json: boolean;\n },\n): Promise<void> {\n const entry: Record<string, unknown> = {\n algoId: opts.algoId,\n algoOrdType: opts.algoOrdType,\n instId: opts.instId,\n };\n if (opts.stopType) entry[\"stopType\"] = opts.stopType;\n const res = await client.privatePost(\"/api/v5/tradingBot/grid/stop-order-algo\", [entry]);\n if (opts.json) return printJson(res.data);\n const r = (res.data as Record<string, unknown>[])[0];\n process.stdout.write(\n `Grid bot stopped: ${r?.[\"algoId\"]} (${r?.[\"sCode\"] === \"0\" ? \"OK\" : r?.[\"sMsg\"]})\\n`,\n );\n}\n"],"mappings":"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","names":["readFileSync","existsSync","join","homedir","path","path","join","homedir","existsSync","readFileSync","parse","path","path","path","writeFileSync","mkdirSync","existsSync","existsSync","mkdirSync","writeFileSync","existsSync","readFileSync","parse","stringify","path","path","os","prompt","path"]}