@pionex/pionex-ai-kit 0.2.35 → 0.2.36
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 +458 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -987,8 +987,8 @@ function runSetup(options) {
|
|
|
987
987
|
);
|
|
988
988
|
}
|
|
989
989
|
var PIONEX_API_DEFAULT_BASE_URL = "https://api.pionex.com";
|
|
990
|
-
var MODULES = ["market", "account", "orders", "bot"];
|
|
991
|
-
var DEFAULT_MODULES = ["market", "account", "orders", "bot"];
|
|
990
|
+
var MODULES = ["market", "account", "orders", "bot", "earn_dual"];
|
|
991
|
+
var DEFAULT_MODULES = ["market", "account", "orders", "bot", "earn_dual"];
|
|
992
992
|
var ConfigError = class extends Error {
|
|
993
993
|
suggestion;
|
|
994
994
|
constructor(message, suggestion) {
|
|
@@ -1163,6 +1163,16 @@ var PionexRestClient = class {
|
|
|
1163
1163
|
const data = await res.json();
|
|
1164
1164
|
return { endpoint: path2, requestTime: (/* @__PURE__ */ new Date()).toISOString(), data };
|
|
1165
1165
|
}
|
|
1166
|
+
async signedDeleteQuery(path2, query = {}) {
|
|
1167
|
+
const { url, headers } = buildSignedRequest(this.config, "DELETE", path2, query, null);
|
|
1168
|
+
const res = await fetch(url, { method: "DELETE", headers });
|
|
1169
|
+
if (!res.ok) {
|
|
1170
|
+
const txt = await readTextSafe(res);
|
|
1171
|
+
throw new PionexApiError(`HTTP ${res.status}: ${txt || res.statusText}`, { status: res.status, endpoint: path2, responseText: txt });
|
|
1172
|
+
}
|
|
1173
|
+
const data = await res.json();
|
|
1174
|
+
return { endpoint: path2, requestTime: (/* @__PURE__ */ new Date()).toISOString(), data };
|
|
1175
|
+
}
|
|
1166
1176
|
};
|
|
1167
1177
|
function registerMarketTools() {
|
|
1168
1178
|
return [
|
|
@@ -2065,8 +2075,291 @@ function registerBotTools() {
|
|
|
2065
2075
|
}
|
|
2066
2076
|
];
|
|
2067
2077
|
}
|
|
2078
|
+
function registerEarnDualTools() {
|
|
2079
|
+
return [
|
|
2080
|
+
// ─── Public endpoints ────────────────────────────────────────────────────
|
|
2081
|
+
{
|
|
2082
|
+
name: "pionex_earn_dual_symbols",
|
|
2083
|
+
module: "earn_dual",
|
|
2084
|
+
isWrite: false,
|
|
2085
|
+
description: "List all trading pairs supported by Dual Investment, optionally filtered by base currency. Supported quote currencies: USDT, USDC, USD, USDXO. No authentication required.",
|
|
2086
|
+
inputSchema: {
|
|
2087
|
+
type: "object",
|
|
2088
|
+
additionalProperties: false,
|
|
2089
|
+
properties: {
|
|
2090
|
+
base: { type: "string", description: "Base currency filter (e.g. BTC, ETH). Omit to return all supported pairs." }
|
|
2091
|
+
}
|
|
2092
|
+
},
|
|
2093
|
+
async handler(args, { client }) {
|
|
2094
|
+
const base = args.base;
|
|
2095
|
+
return (await client.publicGet("/api/v1/earn/dual/symbols", base ? { base } : {})).data;
|
|
2096
|
+
}
|
|
2097
|
+
},
|
|
2098
|
+
{
|
|
2099
|
+
name: "pionex_earn_dual_open_products",
|
|
2100
|
+
module: "earn_dual",
|
|
2101
|
+
isWrite: false,
|
|
2102
|
+
description: "List currently open Dual Investment products for a specific trading pair and direction. DUAL_BASE: invest in base currency (e.g. BTC); DUAL_CURRENCY: invest in investment currency (e.g. USDT). Product ID format: {BASE}-{QUOTE}-{YYMMDD}-{STRIKE}-{C|P}-{CURRENCY}, where C=DUAL_BASE, P=DUAL_CURRENCY. For BTC/ETH use quote=USDXO with currency=USDT or USDC. For other bases use quote=USDT with currency=USDT. No authentication required.",
|
|
2103
|
+
inputSchema: {
|
|
2104
|
+
type: "object",
|
|
2105
|
+
additionalProperties: false,
|
|
2106
|
+
required: ["base", "quote", "type"],
|
|
2107
|
+
properties: {
|
|
2108
|
+
base: { type: "string", description: "Base currency (e.g. BTC, ETH, XRP)" },
|
|
2109
|
+
quote: { type: "string", enum: ["USDT", "USDC", "USDXO"], description: "Quote currency. Use USDXO for BTC/ETH; use USDT for all other base currencies." },
|
|
2110
|
+
type: { type: "string", enum: ["DUAL_BASE", "DUAL_CURRENCY"], description: "DUAL_BASE: invest in base currency (product ID suffix C); DUAL_CURRENCY: invest in investment currency (product ID suffix P)" },
|
|
2111
|
+
currency: { type: "string", description: "Investment currency filter. For BTC/ETH: USDT or USDC. For other pairs: USDT." }
|
|
2112
|
+
}
|
|
2113
|
+
},
|
|
2114
|
+
async handler(args, { client }) {
|
|
2115
|
+
const base = args.base;
|
|
2116
|
+
const quote = args.quote;
|
|
2117
|
+
const type = args.type;
|
|
2118
|
+
const currency = args.currency;
|
|
2119
|
+
const query = { base, quote, type };
|
|
2120
|
+
if (currency) query.currency = currency;
|
|
2121
|
+
return (await client.publicGet("/api/v1/earn/dual/openProducts", query)).data;
|
|
2122
|
+
}
|
|
2123
|
+
},
|
|
2124
|
+
{
|
|
2125
|
+
name: "pionex_earn_dual_prices",
|
|
2126
|
+
module: "earn_dual",
|
|
2127
|
+
isWrite: false,
|
|
2128
|
+
description: "Get latest yield rates and investability status for Dual Investment products. All three parameters (base, quote, productIds) are required. Use USDXO for BTC/ETH pairs; use USDT for all other base currencies. When canInvest is false, profit and baseSize will be empty strings. Always call this before placing an order \u2014 the profit value returned here must be passed unchanged to pionex_earn_dual_invest. No authentication required.",
|
|
2129
|
+
inputSchema: {
|
|
2130
|
+
type: "object",
|
|
2131
|
+
additionalProperties: false,
|
|
2132
|
+
required: ["base", "quote", "productIds"],
|
|
2133
|
+
properties: {
|
|
2134
|
+
base: { type: "string", description: "Base currency (e.g. BTC, ETH, LRC)" },
|
|
2135
|
+
quote: { type: "string", enum: ["USDT", "USDC", "USDXO"], description: "Quote currency. Use USDXO for BTC/ETH pairs; use USDT for all other base currencies." },
|
|
2136
|
+
productIds: {
|
|
2137
|
+
type: "array",
|
|
2138
|
+
items: { type: "string" },
|
|
2139
|
+
description: 'List of product IDs obtained from pionex_earn_dual_open_products (e.g. ["ETH-USDXO-260410-3000-C-USDT", "ETH-USDXO-260410-2900-C-USDT"]).'
|
|
2140
|
+
}
|
|
2141
|
+
}
|
|
2142
|
+
},
|
|
2143
|
+
async handler(args, { client }) {
|
|
2144
|
+
const base = args.base;
|
|
2145
|
+
const quote = args.quote;
|
|
2146
|
+
const productIds = args.productIds;
|
|
2147
|
+
const query = { base, quote };
|
|
2148
|
+
if (productIds && productIds.length > 0) query.productIds = productIds.join(",");
|
|
2149
|
+
return (await client.publicGet("/api/v1/earn/dual/prices", query)).data;
|
|
2150
|
+
}
|
|
2151
|
+
},
|
|
2152
|
+
{
|
|
2153
|
+
name: "pionex_earn_dual_index",
|
|
2154
|
+
module: "earn_dual",
|
|
2155
|
+
isWrite: false,
|
|
2156
|
+
description: "Get real-time index price for a Dual Investment underlying asset. Both base and quote are required. Use USDXO for BTC/ETH pairs; use USDT for all other base currencies. The index price is the reference price used at settlement to determine payout direction. No authentication required.",
|
|
2157
|
+
inputSchema: {
|
|
2158
|
+
type: "object",
|
|
2159
|
+
additionalProperties: false,
|
|
2160
|
+
required: ["base", "quote"],
|
|
2161
|
+
properties: {
|
|
2162
|
+
base: { type: "string", description: "Base currency (e.g. BTC, ETH, LRC)" },
|
|
2163
|
+
quote: { type: "string", enum: ["USDT", "USDC", "USDXO"], description: "Quote currency. Use USDXO for BTC/ETH pairs; use USDT for all other base currencies." }
|
|
2164
|
+
}
|
|
2165
|
+
},
|
|
2166
|
+
async handler(args, { client }) {
|
|
2167
|
+
const base = args.base;
|
|
2168
|
+
const quote = args.quote;
|
|
2169
|
+
return (await client.publicGet("/api/v1/earn/dual/index", { base, quote })).data;
|
|
2170
|
+
}
|
|
2171
|
+
},
|
|
2172
|
+
{
|
|
2173
|
+
name: "pionex_earn_dual_delivery_prices",
|
|
2174
|
+
module: "earn_dual",
|
|
2175
|
+
isWrite: false,
|
|
2176
|
+
description: "Get historical settlement delivery prices for a Dual Investment pair. base is required; quote is optional but recommended to narrow results. Use USDXO for BTC/ETH pairs; use USDT for all other base currencies. The delivery price is the index price recorded at expiry, used to determine the settlement direction. No authentication required.",
|
|
2177
|
+
inputSchema: {
|
|
2178
|
+
type: "object",
|
|
2179
|
+
additionalProperties: false,
|
|
2180
|
+
required: ["base"],
|
|
2181
|
+
properties: {
|
|
2182
|
+
base: { type: "string", description: "Base currency (e.g. BTC, XRP)" },
|
|
2183
|
+
quote: { type: "string", enum: ["USDT", "USDC", "USDXO"], description: "Quote currency filter. Use USDXO for BTC/ETH pairs; use USDT for all other base currencies." },
|
|
2184
|
+
startTime: { type: "integer", description: "Start timestamp in milliseconds" },
|
|
2185
|
+
endTime: { type: "integer", description: "End timestamp in milliseconds" }
|
|
2186
|
+
}
|
|
2187
|
+
},
|
|
2188
|
+
async handler(args, { client }) {
|
|
2189
|
+
const base = args.base;
|
|
2190
|
+
const quote = args.quote;
|
|
2191
|
+
const startTime = args.startTime;
|
|
2192
|
+
const endTime = args.endTime;
|
|
2193
|
+
const query = { base };
|
|
2194
|
+
if (quote) query.quote = quote;
|
|
2195
|
+
if (startTime != null) query.startTime = String(startTime);
|
|
2196
|
+
if (endTime != null) query.endTime = String(endTime);
|
|
2197
|
+
return (await client.publicGet("/api/v1/earn/dual/deliveryPrices", query)).data;
|
|
2198
|
+
}
|
|
2199
|
+
},
|
|
2200
|
+
// ─── View endpoints (authentication required) ────────────────────────────
|
|
2201
|
+
{
|
|
2202
|
+
name: "pionex_earn_dual_balances",
|
|
2203
|
+
module: "earn_dual",
|
|
2204
|
+
isWrite: false,
|
|
2205
|
+
description: "Get authenticated user's Dual Investment account balances. Requires View permission (API key + secret).",
|
|
2206
|
+
inputSchema: {
|
|
2207
|
+
type: "object",
|
|
2208
|
+
additionalProperties: false,
|
|
2209
|
+
properties: {
|
|
2210
|
+
merge: { type: "boolean", description: "When true, merges balances with the same coin across different base currencies." }
|
|
2211
|
+
}
|
|
2212
|
+
},
|
|
2213
|
+
async handler(args, { client }) {
|
|
2214
|
+
const merge = args.merge;
|
|
2215
|
+
const query = {};
|
|
2216
|
+
if (merge != null) query.merge = String(merge);
|
|
2217
|
+
return (await client.signedGet("/api/v1/earn/dual/balances", query)).data;
|
|
2218
|
+
}
|
|
2219
|
+
},
|
|
2220
|
+
{
|
|
2221
|
+
name: "pionex_earn_dual_get_invests",
|
|
2222
|
+
module: "earn_dual",
|
|
2223
|
+
isWrite: false,
|
|
2224
|
+
description: "Batch query Dual Investment orders by client order IDs. Requires View permission (API key + secret).",
|
|
2225
|
+
inputSchema: {
|
|
2226
|
+
type: "object",
|
|
2227
|
+
additionalProperties: false,
|
|
2228
|
+
properties: {
|
|
2229
|
+
base: { type: "string", description: "Base currency (e.g. BTC)" },
|
|
2230
|
+
clientDualIds: {
|
|
2231
|
+
type: "array",
|
|
2232
|
+
items: { type: "string" },
|
|
2233
|
+
description: "List of client-assigned dual investment order IDs to query."
|
|
2234
|
+
}
|
|
2235
|
+
}
|
|
2236
|
+
},
|
|
2237
|
+
async handler(args, { client }) {
|
|
2238
|
+
const base = args.base;
|
|
2239
|
+
const clientDualIds = args.clientDualIds;
|
|
2240
|
+
const body = {};
|
|
2241
|
+
if (base) body.base = base;
|
|
2242
|
+
if (clientDualIds) body.clientDualIds = clientDualIds;
|
|
2243
|
+
return (await client.signedPost("/api/v1/earn/dual/invests", body)).data;
|
|
2244
|
+
}
|
|
2245
|
+
},
|
|
2246
|
+
{
|
|
2247
|
+
name: "pionex_earn_dual_records",
|
|
2248
|
+
module: "earn_dual",
|
|
2249
|
+
isWrite: false,
|
|
2250
|
+
description: "Get paginated Dual Investment history for the authenticated user. Requires View permission (API key + secret).",
|
|
2251
|
+
inputSchema: {
|
|
2252
|
+
type: "object",
|
|
2253
|
+
additionalProperties: false,
|
|
2254
|
+
required: ["base", "endTime"],
|
|
2255
|
+
properties: {
|
|
2256
|
+
base: { type: "string", description: "Base currency (e.g. BTC)" },
|
|
2257
|
+
quote: { type: "string", description: "Quote currency filter. Use USDXO for BTC/ETH; use USDT for others." },
|
|
2258
|
+
currency: { type: "string", description: "Investment currency filter (e.g. USDT, BTC)" },
|
|
2259
|
+
filter: { type: "string", description: "Status filter" },
|
|
2260
|
+
startTime: { type: "integer", description: "Start timestamp in milliseconds" },
|
|
2261
|
+
endTime: { type: "integer", description: "End timestamp in milliseconds (required)" },
|
|
2262
|
+
limit: { type: "integer", description: "Maximum number of records per page (e.g. 20)" }
|
|
2263
|
+
}
|
|
2264
|
+
},
|
|
2265
|
+
async handler(args, { client }) {
|
|
2266
|
+
const base = args.base;
|
|
2267
|
+
const endTime = args.endTime;
|
|
2268
|
+
const quote = args.quote;
|
|
2269
|
+
const currency = args.currency;
|
|
2270
|
+
const filter = args.filter;
|
|
2271
|
+
const startTime = args.startTime;
|
|
2272
|
+
const limit = args.limit;
|
|
2273
|
+
const query = { base, endTime: String(endTime) };
|
|
2274
|
+
if (quote) query.quote = quote;
|
|
2275
|
+
if (currency) query.currency = currency;
|
|
2276
|
+
if (filter) query.filter = filter;
|
|
2277
|
+
if (startTime != null) query.startTime = String(startTime);
|
|
2278
|
+
if (limit != null) query.limit = String(limit);
|
|
2279
|
+
return (await client.signedGet("/api/v1/earn/dual/records", query)).data;
|
|
2280
|
+
}
|
|
2281
|
+
},
|
|
2282
|
+
// ─── Earn/write endpoints (authentication required) ──────────────────────
|
|
2283
|
+
{
|
|
2284
|
+
name: "pionex_earn_dual_invest",
|
|
2285
|
+
module: "earn_dual",
|
|
2286
|
+
isWrite: true,
|
|
2287
|
+
description: "Create a new Dual Investment order. Requires Earn permission (API key + secret). Provide either baseAmount (invest in base currency) or currencyAmount (invest in investment currency), not both. profit must be obtained from pionex_earn_dual_prices and passed unchanged \u2014 a stale or mismatched value will be rejected. Product ID format: {BASE}-{QUOTE}-{YYMMDD}-{STRIKE}-{C|P}-{CURRENCY}, where C=DUAL_BASE, P=DUAL_CURRENCY.",
|
|
2288
|
+
inputSchema: {
|
|
2289
|
+
type: "object",
|
|
2290
|
+
additionalProperties: false,
|
|
2291
|
+
required: ["base"],
|
|
2292
|
+
properties: {
|
|
2293
|
+
base: { type: "string", description: "Base currency (e.g. BTC)" },
|
|
2294
|
+
productId: { type: "string", description: "Product ID to invest in (e.g. BTC-USDXO-260402-68000-P-USDT). Obtain from pionex_earn_dual_open_products." },
|
|
2295
|
+
clientDualId: { type: "string", description: "Client-assigned order ID used as an idempotency key. Recommended to avoid duplicate orders." },
|
|
2296
|
+
baseAmount: { type: "string", description: "Investment amount in base currency (e.g. '0.01'). Mutually exclusive with currencyAmount." },
|
|
2297
|
+
currencyAmount: { type: "string", description: "Investment amount in investment currency (e.g. '100'). Mutually exclusive with baseAmount." },
|
|
2298
|
+
profit: { type: "string", description: "Yield rate from pionex_earn_dual_prices (e.g. '0.0039'). Must be current \u2014 stale values are rejected." }
|
|
2299
|
+
}
|
|
2300
|
+
},
|
|
2301
|
+
async handler(args, { client }) {
|
|
2302
|
+
const body = { base: args.base };
|
|
2303
|
+
if (args.productId) body.productId = args.productId;
|
|
2304
|
+
if (args.clientDualId) body.clientDualId = args.clientDualId;
|
|
2305
|
+
if (args.baseAmount) body.baseAmount = args.baseAmount;
|
|
2306
|
+
if (args.currencyAmount) body.currencyAmount = args.currencyAmount;
|
|
2307
|
+
if (args.profit) body.profit = args.profit;
|
|
2308
|
+
return (await client.signedPost("/api/v1/earn/dual/invest", body)).data;
|
|
2309
|
+
}
|
|
2310
|
+
},
|
|
2311
|
+
{
|
|
2312
|
+
name: "pionex_earn_dual_revoke_invest",
|
|
2313
|
+
module: "earn_dual",
|
|
2314
|
+
isWrite: true,
|
|
2315
|
+
description: "Revoke a pending Dual Investment order before it is matched. Requires Earn permission (API key + secret). Parameters are sent as a JSON request body. Only orders in a pending/unmatched state can be revoked.",
|
|
2316
|
+
inputSchema: {
|
|
2317
|
+
type: "object",
|
|
2318
|
+
additionalProperties: false,
|
|
2319
|
+
required: ["base", "productId", "clientDualId"],
|
|
2320
|
+
properties: {
|
|
2321
|
+
base: { type: "string", description: "Base currency (e.g. BTC)" },
|
|
2322
|
+
clientDualId: { type: "string", description: "Client-assigned dual investment order ID" },
|
|
2323
|
+
productId: { type: "string", description: "Product ID of the order to revoke (e.g. BTC-USDXO-260402-68000-P-USDT)" }
|
|
2324
|
+
}
|
|
2325
|
+
},
|
|
2326
|
+
async handler(args, { client }) {
|
|
2327
|
+
const body = {
|
|
2328
|
+
base: args.base,
|
|
2329
|
+
productId: args.productId,
|
|
2330
|
+
clientDualId: args.clientDualId
|
|
2331
|
+
};
|
|
2332
|
+
return (await client.signedDelete("/api/v1/earn/dual/invest", body)).data;
|
|
2333
|
+
}
|
|
2334
|
+
},
|
|
2335
|
+
{
|
|
2336
|
+
name: "pionex_earn_dual_collect",
|
|
2337
|
+
module: "earn_dual",
|
|
2338
|
+
isWrite: true,
|
|
2339
|
+
description: "Collect settled Dual Investment earnings into the user's spot account. Requires Earn permission (API key + secret). Only orders in a settled state can be collected.",
|
|
2340
|
+
inputSchema: {
|
|
2341
|
+
type: "object",
|
|
2342
|
+
additionalProperties: false,
|
|
2343
|
+
required: ["base", "clientDualId", "productId"],
|
|
2344
|
+
properties: {
|
|
2345
|
+
base: { type: "string", description: "Base currency (e.g. BTC)" },
|
|
2346
|
+
clientDualId: { type: "string", description: "Client-assigned dual investment order ID to collect" },
|
|
2347
|
+
productId: { type: "string", description: "Product ID (e.g. BTC-USDXO-260402-68000-P-USDT)" }
|
|
2348
|
+
}
|
|
2349
|
+
},
|
|
2350
|
+
async handler(args, { client }) {
|
|
2351
|
+
const body = {
|
|
2352
|
+
base: args.base,
|
|
2353
|
+
clientDualId: args.clientDualId,
|
|
2354
|
+
productId: args.productId
|
|
2355
|
+
};
|
|
2356
|
+
return (await client.signedPost("/api/v1/earn/dual/collect", body)).data;
|
|
2357
|
+
}
|
|
2358
|
+
}
|
|
2359
|
+
];
|
|
2360
|
+
}
|
|
2068
2361
|
function allToolSpecs() {
|
|
2069
|
-
return [...registerMarketTools(), ...registerAccountTools(), ...registerOrdersTools(), ...registerBotTools()];
|
|
2362
|
+
return [...registerMarketTools(), ...registerAccountTools(), ...registerOrdersTools(), ...registerBotTools(), ...registerEarnDualTools()];
|
|
2070
2363
|
}
|
|
2071
2364
|
function createToolRunner(client, config) {
|
|
2072
2365
|
const fullConfig = { ...config, modules: [...MODULES] };
|
|
@@ -2228,6 +2521,7 @@ Groups:
|
|
|
2228
2521
|
account Account data (requires auth)
|
|
2229
2522
|
orders Spot orders (requires auth)
|
|
2230
2523
|
bot Bot commands (requires auth) \u2014 use sub-route futures_grid (more bot types may be added later)
|
|
2524
|
+
earn Dual Investment (requires auth for most commands) \u2014 use sub-route dual
|
|
2231
2525
|
|
|
2232
2526
|
Examples:
|
|
2233
2527
|
pionex-trade-cli market depth BTC_USDT --limit 5
|
|
@@ -2240,6 +2534,12 @@ Examples:
|
|
|
2240
2534
|
pionex-trade-cli orders fills-by-order-id --symbol BTC_USDT --order-id 123
|
|
2241
2535
|
pionex-trade-cli bot futures_grid get --bu-order-id <id>
|
|
2242
2536
|
pionex-trade-cli bot futures_grid create --base BTC --quote USDT --bu-order-data-json '{"top":"110000","bottom":"90000","row":100,"grid_type":"arithmetic","trend":"long","leverage":5,"quoteInvestment":"100"}'
|
|
2537
|
+
pionex-trade-cli earn dual symbols --base BTC
|
|
2538
|
+
pionex-trade-cli earn dual open-products --base BTC --quote USDXO --type DUAL_BASE --currency USDT
|
|
2539
|
+
pionex-trade-cli earn dual prices --base BTC --quote USDXO --product-ids BTC-USDXO-260402-68000-P-USDT
|
|
2540
|
+
pionex-trade-cli earn dual invest --base BTC --product-id BTC-USDXO-260402-68000-P-USDT --currency-amount 100 --profit 0.0039
|
|
2541
|
+
pionex-trade-cli earn dual revoke-invest --base BTC --client-dual-id my-order-001 --dry-run
|
|
2542
|
+
pionex-trade-cli earn dual collect --base BTC --client-dual-id my-order-001 --dry-run
|
|
2243
2543
|
|
|
2244
2544
|
Global flags:
|
|
2245
2545
|
--profile <name> Profile in ~/.pionex/config.toml
|
|
@@ -2282,7 +2582,7 @@ function parseJsonFlag(raw, flagName) {
|
|
|
2282
2582
|
async function runPionexCommand(argv) {
|
|
2283
2583
|
const { positionals, flags } = parseFlags(argv);
|
|
2284
2584
|
const group = positionals[0];
|
|
2285
|
-
const command = group === "bot" ? positionals[2] : positionals[1];
|
|
2585
|
+
const command = group === "bot" || group === "earn" ? positionals[2] : positionals[1];
|
|
2286
2586
|
if (!group || group === "help" || group === "--help" || group === "-h") {
|
|
2287
2587
|
printPionexHelp();
|
|
2288
2588
|
return;
|
|
@@ -2520,6 +2820,160 @@ async function runPionexCommand(argv) {
|
|
|
2520
2820
|
}
|
|
2521
2821
|
throw new Error(`Unknown futures_grid command: ${command}`);
|
|
2522
2822
|
}
|
|
2823
|
+
if (group === "earn") {
|
|
2824
|
+
const earnRoute = positionals[1];
|
|
2825
|
+
if (!earnRoute || earnRoute !== "dual") {
|
|
2826
|
+
throw new Error(
|
|
2827
|
+
`Missing or unknown earn route: ${earnRoute ?? "(none)"}. Use: pionex-trade-cli earn dual <command>
|
|
2828
|
+
Commands: symbols, open-products, prices, index, delivery-prices, balances, get-invests, records, invest, revoke-invest, collect`
|
|
2829
|
+
);
|
|
2830
|
+
}
|
|
2831
|
+
if (!command || command === "help" || flags.help === true || flags.h === true) {
|
|
2832
|
+
process.stdout.write(`
|
|
2833
|
+
Usage: pionex-trade-cli earn dual <command> [--flags]
|
|
2834
|
+
|
|
2835
|
+
Public commands (no API key required):
|
|
2836
|
+
symbols List supported trading pairs [--base BTC]
|
|
2837
|
+
open-products List open products --base BTC --quote USDXO --type DUAL_BASE|DUAL_CURRENCY [--currency USDT]
|
|
2838
|
+
(BTC/ETH: --quote USDXO; others: --quote USDT)
|
|
2839
|
+
Product ID format: {BASE}-{QUOTE}-{YYMMDD}-{STRIKE}-{C|P}-{CURRENCY} (C=DUAL_BASE, P=DUAL_CURRENCY)
|
|
2840
|
+
prices Get yield rates --base BTC --quote USDXO --product-ids id1,id2
|
|
2841
|
+
(All three flags required. Always call before invest \u2014 profit value must be passed unchanged.)
|
|
2842
|
+
index Get index price --base BTC --quote USDXO
|
|
2843
|
+
delivery-prices Get delivery prices --base BTC [--quote USDXO] [--start-time ms] [--end-time ms]
|
|
2844
|
+
|
|
2845
|
+
Auth commands (View permission):
|
|
2846
|
+
balances Get Dual Investment balances [--merge]
|
|
2847
|
+
records Get investment history --base BTC --end-time ms [--quote USDT] [--limit 20] [--start-time ms]
|
|
2848
|
+
get-invests Batch query orders [--base BTC] --client-dual-ids id1,id2
|
|
2849
|
+
|
|
2850
|
+
Auth commands (Earn permission, write):
|
|
2851
|
+
invest Create investment --base BTC --product-id <id> (--base-amount N | --currency-amount N) --profit N [--client-dual-id id] [--dry-run]
|
|
2852
|
+
revoke-invest Revoke pending order --base BTC --product-id <id> --client-dual-id <id> [--dry-run]
|
|
2853
|
+
collect Collect settled earnings --base BTC --client-dual-id <id> --product-id <id> [--dry-run]
|
|
2854
|
+
|
|
2855
|
+
Note: For BTC/ETH: --quote USDXO --currency USDT|USDC. For other bases: --quote USDT --currency USDT.
|
|
2856
|
+
`);
|
|
2857
|
+
return;
|
|
2858
|
+
}
|
|
2859
|
+
if (command === "symbols") {
|
|
2860
|
+
const base = typeof flags.base === "string" ? flags.base : void 0;
|
|
2861
|
+
const out = await runTool("pionex_earn_dual_symbols", { base });
|
|
2862
|
+
process.stdout.write(JSON.stringify(out.data, null, 2) + "\n");
|
|
2863
|
+
return;
|
|
2864
|
+
}
|
|
2865
|
+
if (command === "open-products" || command === "openProducts") {
|
|
2866
|
+
const base = typeof flags.base === "string" ? flags.base : void 0;
|
|
2867
|
+
const quote = typeof flags.quote === "string" ? flags.quote : void 0;
|
|
2868
|
+
const type = typeof flags.type === "string" ? flags.type : void 0;
|
|
2869
|
+
const currency = typeof flags.currency === "string" ? flags.currency : void 0;
|
|
2870
|
+
if (!base || !quote || !type) throw new Error("Missing required flags: --base --quote --type (DUAL_BASE|DUAL_CURRENCY)");
|
|
2871
|
+
const out = await runTool("pionex_earn_dual_open_products", { base, quote, type, currency });
|
|
2872
|
+
process.stdout.write(JSON.stringify(out.data, null, 2) + "\n");
|
|
2873
|
+
return;
|
|
2874
|
+
}
|
|
2875
|
+
if (command === "prices") {
|
|
2876
|
+
const base = typeof flags.base === "string" ? flags.base : void 0;
|
|
2877
|
+
const quote = typeof flags.quote === "string" ? flags.quote : void 0;
|
|
2878
|
+
const productIdsRaw = typeof flags["product-ids"] === "string" ? flags["product-ids"] : typeof flags.productIds === "string" ? flags.productIds : void 0;
|
|
2879
|
+
const productIds = productIdsRaw ? productIdsRaw.split(",").map((s) => s.trim()) : void 0;
|
|
2880
|
+
if (!base || !quote || !productIds || productIds.length === 0) throw new Error("Missing required flags: --base --quote --product-ids id1,id2");
|
|
2881
|
+
const out = await runTool("pionex_earn_dual_prices", { base, quote, productIds });
|
|
2882
|
+
process.stdout.write(JSON.stringify(out.data, null, 2) + "\n");
|
|
2883
|
+
return;
|
|
2884
|
+
}
|
|
2885
|
+
if (command === "index") {
|
|
2886
|
+
const base = typeof flags.base === "string" ? flags.base : void 0;
|
|
2887
|
+
const quote = typeof flags.quote === "string" ? flags.quote : void 0;
|
|
2888
|
+
if (!base || !quote) throw new Error("Missing required flags: --base --quote");
|
|
2889
|
+
const out = await runTool("pionex_earn_dual_index", { base, quote });
|
|
2890
|
+
process.stdout.write(JSON.stringify(out.data, null, 2) + "\n");
|
|
2891
|
+
return;
|
|
2892
|
+
}
|
|
2893
|
+
if (command === "delivery-prices" || command === "deliveryPrices") {
|
|
2894
|
+
const base = typeof flags.base === "string" ? flags.base : void 0;
|
|
2895
|
+
if (!base) throw new Error("Missing required flag: --base");
|
|
2896
|
+
const quote = typeof flags.quote === "string" ? flags.quote : void 0;
|
|
2897
|
+
const startTime = flags["start-time"] != null ? Number(flags["start-time"]) : flags.startTime != null ? Number(flags.startTime) : void 0;
|
|
2898
|
+
const endTime = flags["end-time"] != null ? Number(flags["end-time"]) : flags.endTime != null ? Number(flags.endTime) : void 0;
|
|
2899
|
+
const out = await runTool("pionex_earn_dual_delivery_prices", { base, quote, startTime, endTime });
|
|
2900
|
+
process.stdout.write(JSON.stringify(out.data, null, 2) + "\n");
|
|
2901
|
+
return;
|
|
2902
|
+
}
|
|
2903
|
+
if (command === "balances") {
|
|
2904
|
+
const merge = typeof flags.merge === "boolean" ? flags.merge : void 0;
|
|
2905
|
+
const out = await runTool("pionex_earn_dual_balances", { merge });
|
|
2906
|
+
process.stdout.write(JSON.stringify(out.data, null, 2) + "\n");
|
|
2907
|
+
return;
|
|
2908
|
+
}
|
|
2909
|
+
if (command === "get-invests" || command === "getInvests") {
|
|
2910
|
+
const base = typeof flags.base === "string" ? flags.base : void 0;
|
|
2911
|
+
const clientDualIdsRaw = typeof flags["client-dual-ids"] === "string" ? flags["client-dual-ids"] : typeof flags.clientDualIds === "string" ? flags.clientDualIds : void 0;
|
|
2912
|
+
const clientDualIds = clientDualIdsRaw ? clientDualIdsRaw.split(",").map((s) => s.trim()) : void 0;
|
|
2913
|
+
const out = await runTool("pionex_earn_dual_get_invests", { base, clientDualIds });
|
|
2914
|
+
process.stdout.write(JSON.stringify(out.data, null, 2) + "\n");
|
|
2915
|
+
return;
|
|
2916
|
+
}
|
|
2917
|
+
if (command === "records") {
|
|
2918
|
+
const base = typeof flags.base === "string" ? flags.base : void 0;
|
|
2919
|
+
const endTime = flags["end-time"] != null ? Number(flags["end-time"]) : flags.endTime != null ? Number(flags.endTime) : void 0;
|
|
2920
|
+
if (!base || endTime == null) throw new Error("Missing required flags: --base --end-time <ms>");
|
|
2921
|
+
const quote = typeof flags.quote === "string" ? flags.quote : void 0;
|
|
2922
|
+
const currency = typeof flags.currency === "string" ? flags.currency : void 0;
|
|
2923
|
+
const filter = typeof flags.filter === "string" ? flags.filter : void 0;
|
|
2924
|
+
const startTime = flags["start-time"] != null ? Number(flags["start-time"]) : flags.startTime != null ? Number(flags.startTime) : void 0;
|
|
2925
|
+
const limit = flags.limit != null ? Number(flags.limit) : void 0;
|
|
2926
|
+
const out = await runTool("pionex_earn_dual_records", { base, quote, currency, filter, startTime, endTime, limit });
|
|
2927
|
+
process.stdout.write(JSON.stringify(out.data, null, 2) + "\n");
|
|
2928
|
+
return;
|
|
2929
|
+
}
|
|
2930
|
+
if (command === "invest") {
|
|
2931
|
+
const base = typeof flags.base === "string" ? flags.base : void 0;
|
|
2932
|
+
if (!base) throw new Error("Missing required flag: --base");
|
|
2933
|
+
const productId = typeof flags["product-id"] === "string" ? flags["product-id"] : typeof flags.productId === "string" ? flags.productId : void 0;
|
|
2934
|
+
const clientDualId = typeof flags["client-dual-id"] === "string" ? flags["client-dual-id"] : typeof flags.clientDualId === "string" ? flags.clientDualId : void 0;
|
|
2935
|
+
const baseAmount = typeof flags["base-amount"] === "string" ? flags["base-amount"] : typeof flags.baseAmount === "string" ? flags.baseAmount : void 0;
|
|
2936
|
+
const currencyAmount = typeof flags["currency-amount"] === "string" ? flags["currency-amount"] : typeof flags.currencyAmount === "string" ? flags.currencyAmount : void 0;
|
|
2937
|
+
const profit = typeof flags.profit === "string" ? flags.profit : void 0;
|
|
2938
|
+
const payload = { base, productId, clientDualId, baseAmount, currencyAmount, profit };
|
|
2939
|
+
if (dryRun) {
|
|
2940
|
+
process.stdout.write(JSON.stringify({ tool: "pionex_earn_dual_invest", args: payload }, null, 2) + "\n");
|
|
2941
|
+
return;
|
|
2942
|
+
}
|
|
2943
|
+
const out = await runTool("pionex_earn_dual_invest", payload);
|
|
2944
|
+
process.stdout.write(JSON.stringify(out.data, null, 2) + "\n");
|
|
2945
|
+
return;
|
|
2946
|
+
}
|
|
2947
|
+
if (command === "revoke-invest" || command === "revokeInvest") {
|
|
2948
|
+
const base = typeof flags.base === "string" ? flags.base : void 0;
|
|
2949
|
+
const clientDualId = typeof flags["client-dual-id"] === "string" ? flags["client-dual-id"] : typeof flags.clientDualId === "string" ? flags.clientDualId : void 0;
|
|
2950
|
+
const productId = typeof flags["product-id"] === "string" ? flags["product-id"] : typeof flags.productId === "string" ? flags.productId : void 0;
|
|
2951
|
+
if (!base || !clientDualId || !productId) throw new Error("Missing required flags: --base --client-dual-id --product-id");
|
|
2952
|
+
const payload = { base, clientDualId, productId };
|
|
2953
|
+
if (dryRun) {
|
|
2954
|
+
process.stdout.write(JSON.stringify({ tool: "pionex_earn_dual_revoke_invest", args: payload }, null, 2) + "\n");
|
|
2955
|
+
return;
|
|
2956
|
+
}
|
|
2957
|
+
const out = await runTool("pionex_earn_dual_revoke_invest", payload);
|
|
2958
|
+
process.stdout.write(JSON.stringify(out.data, null, 2) + "\n");
|
|
2959
|
+
return;
|
|
2960
|
+
}
|
|
2961
|
+
if (command === "collect") {
|
|
2962
|
+
const base = typeof flags.base === "string" ? flags.base : void 0;
|
|
2963
|
+
const clientDualId = typeof flags["client-dual-id"] === "string" ? flags["client-dual-id"] : typeof flags.clientDualId === "string" ? flags.clientDualId : void 0;
|
|
2964
|
+
const productId = typeof flags["product-id"] === "string" ? flags["product-id"] : typeof flags.productId === "string" ? flags.productId : void 0;
|
|
2965
|
+
if (!base || !clientDualId || !productId) throw new Error("Missing required flags: --base --client-dual-id --product-id");
|
|
2966
|
+
const payload = { base, clientDualId, productId };
|
|
2967
|
+
if (dryRun) {
|
|
2968
|
+
process.stdout.write(JSON.stringify({ tool: "pionex_earn_dual_collect", args: payload }, null, 2) + "\n");
|
|
2969
|
+
return;
|
|
2970
|
+
}
|
|
2971
|
+
const out = await runTool("pionex_earn_dual_collect", payload);
|
|
2972
|
+
process.stdout.write(JSON.stringify(out.data, null, 2) + "\n");
|
|
2973
|
+
return;
|
|
2974
|
+
}
|
|
2975
|
+
throw new Error(`Unknown earn dual command: ${command}`);
|
|
2976
|
+
}
|
|
2523
2977
|
throw new Error(`Unknown group: ${group}`);
|
|
2524
2978
|
}
|
|
2525
2979
|
function main() {
|