bingx-swap-trade
BingX perpetual swap trading — place/cancel orders, manage positions, set leverage, and configure margin settings. Use when the user asks about BingX swap trading, order placement, cancellation, position management, leverage, or margin type settings.
How do I install this agent skill?
npx skills add https://github.com/bingx-api/api-ai-skills --skill bingx-swap-tradeIs this agent skill safe to install?
- Gen Agent Trust Hubpass
This skill facilitates perpetual swap trading on the BingX exchange. It incorporates security best practices, including mandatory user confirmation for live trading, strict input validation to prevent parameter injection, and secure HMAC-SHA256 authentication logic. The implementation uses standard libraries and communicates exclusively with official BingX API endpoints.
- Socketpass
No alerts
- Snykwarn
Risk: MEDIUM · 1 issue
- Runlayerpass
2 files scanned · No issues
- ZeroLeakspass
1 finding · Score: 86/100
What does this agent skill do?
BingX Swap Trade
Authenticated trading endpoints for BingX perpetual futures. All endpoints require HMAC SHA256 signature authentication.
Base URLs: see references/base-urls.md | Authentication: see references/authentication.md
Quick Reference
| Endpoint | Method | Description | Authentication |
|---|---|---|---|
/openApi/swap/v2/trade/order | POST | Place a new order | Yes |
/openApi/swap/v2/trade/order/test | POST | Test order placement (no fill) | Yes |
/openApi/swap/v2/trade/batchOrders | POST | Place multiple orders (batch, max 5) | Yes |
/openApi/swap/v2/trade/order | DELETE | Cancel an order | Yes |
/openApi/swap/v2/trade/batchOrders | DELETE | Cancel multiple orders | Yes |
/openApi/swap/v2/trade/allOpenOrders | DELETE | Cancel all open orders | Yes |
/openApi/swap/v2/trade/cancelAllAfter | POST | Auto-cancel countdown (kill switch) | Yes |
/openApi/swap/v2/trade/closeAllPositions | POST | Close all positions | Yes |
/openApi/swap/v1/trade/closePosition | POST | Close position by positionId | Yes |
/openApi/swap/v2/trade/positionMargin | POST | Adjust isolated margin amount | Yes |
/openApi/swap/v1/positionMargin/history | GET | Query margin adjustment history | Yes |
/openApi/swap/v2/trade/openOrders | GET | Query open orders | Yes |
/openApi/swap/v2/trade/openOrder | GET | Query a single open order | Yes |
/openApi/swap/v2/trade/order | GET | Query an order by ID | Yes |
/openApi/swap/v1/trade/fullOrder | GET | Query full order details | Yes |
/openApi/swap/v2/trade/allOrders | GET | Query all historical orders | Yes |
/openApi/swap/v2/trade/forceOrders | GET | Query liquidation/ADL orders | Yes |
/openApi/swap/v2/trade/allFillOrders | GET | Query trade fill history | Yes |
/openApi/swap/v2/trade/fillHistory | GET | Query historical trade fill details | Yes |
/openApi/swap/v1/twap/openOrders | GET | Query open TWAP orders | Yes |
/openApi/swap/v1/twap/historyOrders | GET | Query TWAP order history | Yes |
/openApi/swap/v1/twap/orderDetail | GET | Query TWAP order details | Yes |
/openApi/swap/v1/twap/order | POST | Create TWAP order | Yes |
/openApi/swap/v1/twap/cancelOrder | POST | Cancel TWAP order | Yes |
/openApi/swap/v1/trade/positionHistory | GET | Query position history | Yes |
/openApi/swap/v1/maintMarginRatio | GET | Query maintenance margin ratio | Yes |
/openApi/swap/v2/trade/marginType | GET | Query margin type | Yes |
/openApi/swap/v2/trade/marginType | POST | Set margin type (ISOLATED/CROSSED) | Yes |
/openApi/swap/v2/trade/leverage | GET | Query current leverage | Yes |
/openApi/swap/v2/trade/leverage | POST | Set leverage | Yes |
/openApi/swap/v1/positionSide/dual | GET | Query position mode | Yes |
/openApi/swap/v1/positionSide/dual | POST | Set position mode | Yes |
/openApi/swap/v1/trade/assetMode | GET | Query asset mode (single/multi-asset) | Yes |
/openApi/swap/v1/trade/assetMode | POST | Set asset mode (single/multi-asset) | Yes |
/openApi/swap/v1/trade/multiAssetsRules | GET | Query multi-asset margin rules | Yes |
/openApi/swap/v1/user/marginAssets | GET | Query margin assets for multi-asset mode | Yes |
/openApi/swap/v1/trade/autoAddMargin | POST | Set auto-add margin for position | Yes |
/openApi/swap/v1/trade/reverse | POST | Reverse position (one-click flip) | Yes |
/openApi/swap/v1/trade/cancelReplace | POST | Cancel and replace an order (atomic) | Yes |
/openApi/swap/v1/trade/batchCancelReplace | POST | Batch cancel and replace orders | Yes |
/openApi/swap/v1/trade/amend | POST | Modify an existing open order | Yes |
/openApi/swap/v2/trade/getVst | POST | Get VST (virtual simulation trading) | Yes |
Parameters
Order Parameters
- symbol: Trading pair in
BASE-QUOTEformat (e.g.,BTC-USDT,ETH-USDT) - side: Order direction —
BUYorSELL - positionSide: Position direction —
LONGorSHORT(hedge mode) /BOTH(one-way mode) - type: Order type (see Enums)
- quantity: Order quantity in coins (e.g.,
0.01for BTC-USDT); still mandatory forSTOP_MARKETandTAKE_PROFIT_MARKETwhenclosePosition: true - price: Limit price (required for
LIMIT,STOP,TAKE_PROFITtypes) - stopPrice: Trigger price (required for
STOP_MARKET,STOP,TAKE_PROFIT_MARKET,TAKE_PROFIT) - timeInForce:
GTC|IOC|FOK|PostOnly— defaultGTC; required forLIMITtype - clientOrderId: Custom order ID, 1–40 chars (converted to lowercase)
- recvWindow: Request validity window in milliseconds (max 60000)
- orderId: System order ID (for cancel/query operations)
- workingType: Price source used to trigger conditional orders —
MARK_PRICE(mark price) orCONTRACT_PRICE(last traded price, default) - stopGuaranteed:
true|false— Whether stop-loss execution is guaranteed; guaranteed stops may incur an additional fee - closePosition:
true|false— When the trigger fires, close the entire position quantity. Supported only forSTOP_MARKETandTAKE_PROFIT_MARKET;quantityandstopPriceremain mandatory. Do not combine it withreduceOnly. - reduceOnly:
true|false— Order can only reduce (never increase) position size. Do not send this parameter in Hedge Mode. - activationPrice: Activation price for
TRAILING_STOP_MARKETorders (optional; defaults to current market price when omitted) - priceRate: Trailing callback rate for
TRAILING_STOP_MARKET/TRAILING_TP_SLorders (e.g.,0.05= 5%) - stopLoss: JSON-string query parameter — Attach a stop-loss to a
MARKET/LIMITorder. Build and validate the nested object first, then callJSON.stringifyexactly once. - takeProfit: JSON-string query parameter — Attach a take-profit to a
MARKET/LIMITorder. Build and validate the nested object first, then callJSON.stringifyexactly once.
Position Parameters
- leverage: Integer leverage multiplier (e.g.,
10,20,50) - marginType:
ISOLATEDorCROSSED - dualSidePosition:
"true"(hedge mode) or"false"(one-way mode) - positionId: Position ID string. Not required for regular Hedge Mode orders; required when closing a position in Separate Isolated mode and by endpoints that explicitly identify a position.
- amount: Margin adjustment amount in USDT (used by
positionMarginendpoint) - direction_type:
1(add margin) or2(reduce margin) (used bypositionMarginendpoint)
Enums
type (Order type):
MARKET— Market order (fills immediately at best price; attachstopLoss/takeProfitobjects here)LIMIT— Limit order (requirespriceandtimeInForce; attachstopLoss/takeProfitobjects here)STOP_MARKET— Stop-loss market (triggers atstopPrice, executes as market)STOP— Stop-loss limit (triggers atstopPrice, executes as limit atprice)TAKE_PROFIT_MARKET— Take-profit market (triggers atstopPrice, executes as market)TAKE_PROFIT— Take-profit limit (triggers atstopPrice, executes as limit atprice)TRAILING_STOP_MARKET— Trailing stop market; usespriceRate(required) and optionalactivationPriceTRAILING_TP_SL— Trailing TP/SL for an existing position; links to position viasymbol+positionSide; usespriceRate
side: BUY | SELL
positionSide: LONG | SHORT | BOTH
marginType: ISOLATED | CROSSED
timeInForce: GTC | IOC | FOK | PostOnly
workingType (trigger price source for conditional orders):
MARK_PRICE— Use mark price to evaluate trigger conditionCONTRACT_PRICE— Use last traded price (default)
Stop-Loss / Take-Profit Object Structure
When attaching stopLoss or takeProfit to a MARKET or LIMIT order:
{
"stopLoss": {
"type": "STOP_MARKET", // "STOP_MARKET" or "STOP"
"stopPrice": 29000, // required: trigger price
"price": 28900, // required only for type "STOP" (limit execution price)
"workingType": "MARK_PRICE", // "MARK_PRICE" or "CONTRACT_PRICE"
"stopGuaranteed": false // true = guaranteed execution (extra fee may apply)
},
"takeProfit": {
"type": "TAKE_PROFIT_MARKET", // "TAKE_PROFIT_MARKET" or "TAKE_PROFIT"
"stopPrice": 35000, // required: trigger price
"price": 35100, // required only for type "TAKE_PROFIT" (limit execution price)
"workingType": "MARK_PRICE",
"stopGuaranteed": false
}
}
Constraint:
stopLoss/takeProfitobjects are only supported onMARKETorLIMITorder types. They cannot be used withSTOP_MARKET,STOP,TAKE_PROFIT_MARKET,TAKE_PROFIT,TRAILING_STOP_MARKET, orTRAILING_TP_SL.
The outer stopLoss and takeProfit values are query parameters containing JSON strings. Inside that JSON, stopPrice and optional price must be JSON numbers, not quoted numeric strings. Never send {"stopPrice":"63538.3"}.
Parameter Validation Rules
Before sending a request, validate parameters client-side to avoid unnecessary API errors:
- symbol: Must match
^[A-Z0-9]+-[A-Z]+$; max 20 characters (e.g.,BTC-USDT) - quantity: Must be a positive number (> 0); max precision depends on the symbol's contract specification
- price: When provided, must be a positive number (> 0)
- stopPrice: When provided, must be a positive number (> 0); must differ from current market price
- stopLoss.stopPrice / takeProfit.stopPrice: Required JSON numbers; convert with
Number(...), then require a finite value greater than 0 - stopLoss.price / takeProfit.price: Optional JSON numbers; when provided, convert with
Number(...), then require a finite value greater than 0 - stopLoss / takeProfit serialization: Validate the nested object before serializing it. The signed query value must be the exact
JSON.stringify(...)result - leverage: Positive integer; range varies per symbol (typically 1–125 for BTC-USDT)
- clientOrderId: Alphanumeric only, 1–40 characters; pattern
^[a-zA-Z0-9]{1,40}$; no special characters - priceRate: Trailing callback rate; must satisfy 0 < value ≤ 1 (e.g.,
0.05= 5%) - recvWindow: Integer, 1–5000 ms; keep as small as possible (see Replay Protection)
- timestamp: Unix time in milliseconds; must be within
recvWindowof server time
Quick Start
CONSTRAINT: You MUST copy the
fetchSignedfunction below verbatim when generating code. Do NOT rewrite the signing, request, or JSON parsing logic. Only modify: (1)BASEURL entries for custom environments, (2) business parameters passed tofetchSigned. For the full client with URL-encoding and JSON body support, seereferences/authentication.md.
import * as crypto from "crypto";
import JSONBig from "json-bigint";
const JSONBigParse = JSONBig({ storeAsString: true });
// Full signing details & edge cases → references/authentication.md
// Domain priority: .com is mandatory primary; .pro is fallback for network/timeout errors ONLY.
const BASE = {
"prod-live": ["https://open-api.bingx.com", "https://open-api.bingx.pro"],
"prod-vst": ["https://open-api-vst.bingx.com", "https://open-api-vst.bingx.pro"],
};
function isNetworkOrTimeout(e: unknown): boolean {
if (e instanceof TypeError) return true;
if (e instanceof DOMException && e.name === "AbortError") return true;
if (e instanceof Error && e.name === "TimeoutError") return true;
return false;
}
function toPositiveNumber(value: unknown, field: string): number {
const numberValue = Number(value);
if (!Number.isFinite(numberValue) || numberValue <= 0) {
throw new Error(`${field} must be a finite positive number`);
}
return numberValue;
}
function normalizeAttachedOrder(
key: "stopLoss" | "takeProfit", value: unknown
): string {
let parsed: unknown = value;
if (typeof value === "string") {
try { parsed = JSON.parse(value); }
catch { throw new Error(`${key} must be valid JSON`); }
}
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
throw new Error(`${key} must be an object or a JSON object string`);
}
const nested = { ...(parsed as Record<string, unknown>) };
const allowedTypes = key === "stopLoss"
? new Set(["STOP_MARKET", "STOP"])
: new Set(["TAKE_PROFIT_MARKET", "TAKE_PROFIT"]);
if (typeof nested.type !== "string" || !allowedTypes.has(nested.type)) {
throw new Error(`${key}.type is invalid`);
}
nested.stopPrice = toPositiveNumber(nested.stopPrice, `${key}.stopPrice`);
if (nested.price !== undefined) {
nested.price = toPositiveNumber(nested.price, `${key}.price`);
}
if (nested.workingType !== undefined &&
nested.workingType !== "MARK_PRICE" &&
nested.workingType !== "CONTRACT_PRICE") {
throw new Error(`${key}.workingType is invalid`);
}
if (nested.stopGuaranteed !== undefined &&
typeof nested.stopGuaranteed !== "boolean") {
throw new Error(`${key}.stopGuaranteed must be a boolean`);
}
return JSON.stringify(nested);
}
function normalizeParams(params: Record<string, unknown>): Record<string, unknown> {
const normalized = { ...params };
if (normalized.price !== undefined) {
normalized.price = toPositiveNumber(normalized.price, "price");
}
for (const key of ["stopLoss", "takeProfit"] as const) {
if (normalized[key] !== undefined) {
normalized[key] = normalizeAttachedOrder(key, normalized[key]);
}
}
return normalized;
}
function serializeParamValue(value: unknown): string {
if (value !== null && typeof value === "object") return JSON.stringify(value);
return String(value);
}
function validateParams(params: Record<string, unknown>): void {
const FORBIDDEN = /[&=?#\r\n]/;
for (const [k, v] of Object.entries(params)) {
const s = serializeParamValue(v);
if (FORBIDDEN.test(s)) throw new Error(`Param "${k}" has forbidden char in: "${s}"`);
}
}
async function fetchSigned(env: string, apiKey: string, secretKey: string,
method: "GET" | "POST" | "DELETE", path: string, params: Record<string, unknown> = {}
) {
const urls = BASE[env] ?? BASE["prod-live"];
const normalized = normalizeParams(params);
const all = { ...normalized, timestamp: Date.now() };
validateParams(all);
const qs = Object.keys(all).sort()
.map(k => `${k}=${serializeParamValue(all[k])}`).join("&");
const sig = crypto.createHmac("sha256", secretKey).update(qs).digest("hex");
const signed = `${qs}&signature=${sig}`;
for (const base of urls) {
try {
const url = method === "POST" ? `${base}${path}` : `${base}${path}?${signed}`;
const res = await fetch(url, {
method,
headers: { "X-BX-APIKEY": apiKey, "X-SOURCE-KEY": "BX-AI-SKILL",
...(method === "POST" ? { "Content-Type": "application/x-www-form-urlencoded" } : {}) },
body: method === "POST" ? signed : undefined,
signal: AbortSignal.timeout(10000),
});
const json = JSONBigParse.parse(await res.text());
if (json.code !== 0) throw new Error(`BingX error ${json.code}: ${json.msg}`);
return json.data;
} catch (e) {
if (!isNetworkOrTimeout(e) || base === urls[urls.length - 1]) throw e;
}
}
}
Code Usage Rules
- MUST copy
fetchSignedverbatim -- do not simplify or rewrite - MUST use
json-bigint(JSONBigParse.parse) for response parsing -- notJSON.parse - MUST include
X-SOURCE-KEY: BX-AI-SKILLheader on every request - MUST NOT remove the domain fallback loop or
isNetworkOrTimeoutcheck - MUST normalize and serialize all business parameters before creating the timestamp and signature. If any parameter changes, discard the previous timestamp/signature and sign a new request
- MUST NOT interpolate object values directly with
${params[k]}; object values must be serialized withJSON.stringify, otherwise they become[object Object]
Common Calls
Place a market buy order:
const order = await fetchSigned("prod-live", API_KEY, SECRET, "POST",
"/openApi/swap/v2/trade/order", {
symbol: "BTC-USDT",
side: "BUY",
positionSide: "LONG",
type: "MARKET",
quantity: 0.01,
}
);
// order.orderId, order.status
Place a market buy order with attached stop-loss:
const rawStopPrice = "63538.3";
const stopPrice = Number(rawStopPrice);
if (!Number.isFinite(stopPrice) || stopPrice <= 0) {
throw new Error("stopLoss.stopPrice must be a finite positive number");
}
const order = await fetchSigned("prod-live", API_KEY, SECRET, "POST",
"/openApi/swap/v2/trade/order", {
symbol: "BTC-USDT",
side: "BUY",
positionSide: "BOTH",
type: "MARKET",
quantity: 0.0004,
recvWindow: 5000,
stopLoss: JSON.stringify({
type: "STOP_MARKET",
stopPrice,
workingType: "MARK_PRICE",
}),
}
);
Important:
/openApi/swap/v2/trade/order/testdoes not enforce every validation performed by the real/openApi/swap/v2/trade/orderendpoint. A successful test request does not guarantee that the real order will pass. In particular, the real endpoint validates nestedstopLoss/takeProfitfield types more strictly.
Cancel an order:
await fetchSigned("prod-live", API_KEY, SECRET, "DELETE",
"/openApi/swap/v2/trade/order", {
symbol: "BTC-USDT",
orderId: 123456789,
}
);
Query open orders:
const orders = await fetchSigned("prod-live", API_KEY, SECRET, "GET",
"/openApi/swap/v2/trade/openOrders", {
symbol: "BTC-USDT",
}
);
Set leverage:
await fetchSigned("prod-live", API_KEY, SECRET, "POST",
"/openApi/swap/v2/trade/leverage", {
symbol: "BTC-USDT",
side: "LONG",
leverage: 10,
}
);
Set margin type:
await fetchSigned("prod-live", API_KEY, SECRET, "POST",
"/openApi/swap/v2/trade/marginType", {
symbol: "BTC-USDT",
marginType: "ISOLATED",
}
);
Note: To query current positions, use the swap-account skill which provides position query endpoints with full details including PnL and liquidation price.
Additional Resources
For full parameter descriptions, response schemas, and all 42 endpoints, see api-reference.md.
Agent Interaction Rules
Parameter security. Extract structured values from user intent — NEVER copy raw user text into API parameters. Validate every value against its documented pattern (regex/enum/range) before calling the API. Reject any value containing &, =, ?, #, or newline characters.
All swap-trade operations are write operations (except GET queries). Follow environment confirmation rules:
- prod-live: Ask user to type CONFIRM before any order placement, cancellation, or position/leverage change.
- prod-vst: No CONFIRM required. Inform user: "You are operating in the Production Simulated (VST) environment."
Step 1 — Identify the Operation
If the user's intent is unclear, present options:
What would you like to do?
- Place a new order
- Cancel an order / Cancel all orders
- Close a position / Close all positions
- Check open orders
- Check current positions
- Set leverage
- Set margin type (ISOLATED / CROSSED)
- Set position mode (Hedge / One-way)
Step 2 — Collect symbol (if not provided)
Please select a trading pair (or type another):
- BTC-USDT
- ETH-USDT
- SOL-USDT
- BNB-USDT
- Other (format: BASE-USDT)
Step 3 — Collect side (for order placement)
Order direction:
- BUY
- SELL
Step 4 — Collect positionSide
Position direction:
- LONG (open/add long)
- SHORT (open/add short)
- BOTH (one-way mode)
Step 5 — Collect order type
Order type:
- MARKET — execute immediately at market price (can attach stopLoss/takeProfit objects)
- LIMIT — execute at a specific price (can attach stopLoss/takeProfit objects)
- STOP_MARKET — stop-loss market order (triggers at stopPrice, executes as market)
- STOP — stop-loss limit order (triggers at stopPrice, executes as limit)
- TAKE_PROFIT_MARKET — take-profit market order (triggers at stopPrice)
- TAKE_PROFIT — take-profit limit order (triggers at stopPrice, executes as limit)
- TRAILING_STOP_MARKET — trailing stop for new position (requires priceRate; optional activationPrice)
- TRAILING_TP_SL — trailing TP/SL for an existing position (links via symbol + positionSide; requires priceRate)
Step 6 — Collect quantity and price
- Ask for quantity in coins (e.g., 0.01 BTC for BTC-USDT). For
STOP_MARKETandTAKE_PROFIT_MARKET, quantity remains mandatory when usingclosePosition: true. - If type is
LIMIT,STOP, orTAKE_PROFIT: also ask forprice. - If type is
STOP_MARKET,STOP,TAKE_PROFIT_MARKET, orTAKE_PROFIT: also ask forstopPrice. - If type is
TRAILING_STOP_MARKETorTRAILING_TP_SL: ask forpriceRate(e.g., 0.05 = 5%) and optionallyactivationPrice. - If type is
MARKETorLIMIT: optionally offer to attach astopLossand/ortakeProfitobject (ask for trigger price and type).
Optional advanced parameters (ask only if relevant or user mentions them):
workingType: trigger price source —MARK_PRICEorCONTRACT_PRICE(default)reduceOnly:trueto ensure the order only reduces position size; do not send it in Hedge ModeclosePosition:trueto close the entire position when triggered; only forSTOP_MARKETandTAKE_PROFIT_MARKET, with bothquantityandstopPricestill requiredstopGuaranteed:truefor guaranteed stop execution (extra fee may apply)
Step 7 — Confirm (prod-live only)
For prod-live environment, present a summary and ask:
You are about to place the following order on Production Live:
- Symbol: BTC-USDT
- Side: BUY / LONG
- Type: MARKET
- Quantity: 0.01
Type CONFIRM to proceed, or anything else to cancel.
Step 8 — Execute and report
Execute the API call and return the order ID and status to the user.
Cancel Order Flow
- Ask for
orderId(orclientOrderId) if not provided. - For
prod-live: ask for CONFIRM. - Execute DELETE
/openApi/swap/v2/trade/order.
Close Position Flow
- Ask for symbol if not provided.
- Present options: close specific position (LONG/SHORT) or close all.
- For
prod-live: ask for CONFIRM. - Use POST
/openApi/swap/v2/trade/closeAllPositionsor place a reverse MARKET order.
Leverage Settings Flow
- Ask for symbol if not provided.
- Ask for position side (LONG / SHORT / both).
- Ask for leverage value (e.g., 1–125).
- For
prod-live: ask for CONFIRM. - Execute POST
/openApi/swap/v2/trade/leverage.
Margin Type Flow
- Ask for symbol if not provided.
- Present options: ISOLATED or CROSSED.
- For
prod-live: ask for CONFIRM. - Execute POST
/openApi/swap/v2/trade/marginType.
Position Mode Flow
- Present options: Hedge mode (
dualSidePosition: true) or One-way mode (dualSidePosition: false). - For
prod-live: ask for CONFIRM. - Execute POST
/openApi/swap/v1/positionSide/dual.
How can the creator link this skill?
Add the canonical catalog link to the repository README so users can inspect current installs and available audits. The publishing guide covers the complete discovery path.
<a href="https://skillzs.dev/skills/bingx-api/api-ai-skills/bingx-swap-trade">View bingx-swap-trade on skillZs</a>