ZetariumZetariumDex

Futures Configuration

Set leverage, margin mode, and position mode (one-way / hedge).

Code samples assume the signed-request helper from Endpoints / Overview → Client setup.

POST /v2/futures/leverage

Set the leverage for a symbol.

AuthAPI_KEY (TRADE)

Body

{
  symbol: string;
  leverage: number;                  // 1 – 125
  forceWithOpenPosition?: boolean;   // default false
}

Behavior

  • No open position on the symbol → leverage is updated immediately, 200.
  • Open position present without forceWithOpenPosition: true409:
{
  "ok": false,
  "error": "Symbol has an open position. Re-send with forceWithOpenPosition=true to confirm leverage change (this re-prices your liquidation level).",
  "code": "OPEN_POSITION_LEVERAGE_GUARD"
}
  • With forceWithOpenPosition: true the venue is called; if the venue accepts and the liquidation re-pricing succeeds, response is 200.

Recommended pattern — on 409 with code: OPEN_POSITION_LEVERAGE_GUARD, escalate to the user (or your risk model) and only then resend with forceWithOpenPosition: true.

Response

{ "ok": true, "data": { "leverage": 20, "symbol": "BTCUSDT" } }

Example

TS=$(($(date +%s) * 1000)); QUERY="timestamp=${TS}"
SIG=$(sign "$SECRET" "$QUERY")
curl -X POST -H "X-API-KEY: $API_KEY" -H "Content-Type: application/json" \
  -d '{"symbol":"BTCUSDT","leverage":20}' \
  "$BASE_URL/v2/futures/leverage?${QUERY}&signature=${SIG}"
const res = await signedRequest('POST', '/v2/futures/leverage', {
  body: { symbol: 'BTCUSDT', leverage: 20 },
});
res = signed_request("POST", "/v2/futures/leverage",
    body={"symbol": "BTCUSDT", "leverage": 20}).json()
res, _ := zdex.SignedRequest("POST", "/v2/futures/leverage", nil,
    map[string]any{"symbol": "BTCUSDT", "leverage": 20})
let res = signed_request(reqwest::Method::POST, "/v2/futures/leverage",
    &[], Some(&json!({ "symbol": "BTCUSDT", "leverage": 20 }))).await?;
$res = signed_request('POST', '/v2/futures/leverage', [],
    ['symbol' => 'BTCUSDT', 'leverage' => 20]);

POST /v2/futures/margin-type

Switch between cross and isolated margin.

AuthAPI_KEY (TRADE)

Body

{
  symbol: string;
  marginType: "ISOLATED" | "CROSSED";
  forceWithOpenPosition?: boolean;
}

Same guard logic as leverage — open positions require forceWithOpenPosition: true, otherwise 409 with code: OPEN_POSITION_MARGIN_GUARD.

Response

{ "ok": true, "data": { "marginType": "ISOLATED", "symbol": "BTCUSDT" } }

No-op response — when the venue reports the symbol is already in the target mode, the response carries an extra unchanged: true field:

{ "ok": true, "data": { "marginType": "ISOLATED", "symbol": "BTCUSDT", "unchanged": true } }

Branch on unchanged === true if you need to suppress "switched" toasts.

Example

TS=$(($(date +%s) * 1000)); QUERY="timestamp=${TS}"
SIG=$(sign "$SECRET" "$QUERY")
curl -X POST -H "X-API-KEY: $API_KEY" -H "Content-Type: application/json" \
  -d '{"symbol":"BTCUSDT","marginType":"ISOLATED"}' \
  "$BASE_URL/v2/futures/margin-type?${QUERY}&signature=${SIG}"
const res = await signedRequest('POST', '/v2/futures/margin-type', {
  body: { symbol: 'BTCUSDT', marginType: 'ISOLATED' },
});
res = signed_request("POST", "/v2/futures/margin-type",
    body={"symbol": "BTCUSDT", "marginType": "ISOLATED"}).json()
res, _ := zdex.SignedRequest("POST", "/v2/futures/margin-type", nil,
    map[string]any{"symbol": "BTCUSDT", "marginType": "ISOLATED"})
let res = signed_request(reqwest::Method::POST, "/v2/futures/margin-type",
    &[], Some(&json!({ "symbol": "BTCUSDT", "marginType": "ISOLATED" }))).await?;
$res = signed_request('POST', '/v2/futures/margin-type', [],
    ['symbol' => 'BTCUSDT', 'marginType' => 'ISOLATED']);

POST /v2/futures/close-and-switch-margin

Atomically close every open position and cancel every working order on a symbol, then flip the sub-account-wide margin mode. Use this when the plain POST /v2/futures/margin-type returns OPEN_POSITION_MARGIN_GUARD (or OPEN_POSITION_MARGIN_REJECT) and the trader has accepted closing the position to make the switch happen.

AuthAPI_KEY (TRADE)

Body

{
  symbol: string;                              // "BTCUSDT" — drives close + cancel
  targetMarginType: "ISOLATED" | "CROSSED";    // mode to flip to
}

Behavior — runs three legs sequentially. Each completes before the next starts, but there is no rollback: if leg 2 succeeds and leg 3 fails, your position is closed and you'll need to retry the toggle from the UI.

  1. Cancel every working order on the symbol (PENDING_NEW, NEW, PARTIALLY_FILLED).
  2. Close every open position on the symbol with reduce-only MARKET orders. In hedge mode both LONG and SHORT legs are closed independently.
  3. Call the venue's setMarginType (which is sub-wide, not per-symbol — same scope as /v2/futures/margin-type).

Response — full success

{
  "ok": true,
  "data": {
    "symbol": "BTCUSDT",
    "marginType": "ISOLATED",
    "canceledOrders": ["12345678", "12345679"],
    "closedPositions": [
      { "id": "cmpos...", "venuePositionId": "venue_pos_42", "quantity": "0.5" }
    ]
  }
}

Response — partial failure (leg 3 failed after leg 2 succeeded)

502 with the legs that did complete echoed back so the client can explain to the trader exactly what state the account is in:

{
  "ok": false,
  "error": "Position closed but margin mode switch failed — please retry the toggle from the UI.",
  "stage": "switch",
  "closedPositions": [/* same shape as success */],
  "canceledOrders": ["12345678"],
  "details": { /* venue raw error */ }
}

Response — leg 2 (close) failed

502 with stage: "close" and the venue's own error message surfaced as error so the trader knows whether it was a margin conflict, a quantity reject, or insufficient balance:

{
  "ok": false,
  "error": "Failed to close position before margin mode switch: <venue message>",
  "stage": "close",
  "venueErrorCode": -2010,
  "details": { /* venue raw error */ }
}

The endpoint detects "already closed venue-side" close failures (-2010 + an "already closed/filled" or "reduce-only reject" message) and reconciles the DB row instead of failing — your trader sees a clean success in that race.

Side effectsorder_canceled, position_update (one per closed position) WebSocket pushes.

Example

TS=$(($(date +%s) * 1000)); QUERY="timestamp=${TS}"
SIG=$(sign "$SECRET" "$QUERY")
curl -X POST -H "X-API-KEY: $API_KEY" -H "Content-Type: application/json" \
  -d '{"symbol":"BTCUSDT","targetMarginType":"ISOLATED"}' \
  "$BASE_URL/v2/futures/close-and-switch-margin?${QUERY}&signature=${SIG}"
const res = await signedRequest('POST', '/v2/futures/close-and-switch-margin', {
  body: { symbol: 'BTCUSDT', targetMarginType: 'ISOLATED' },
});
res = signed_request("POST", "/v2/futures/close-and-switch-margin",
    body={"symbol": "BTCUSDT", "targetMarginType": "ISOLATED"}).json()
res, _ := zdex.SignedRequest("POST", "/v2/futures/close-and-switch-margin", nil,
    map[string]any{"symbol": "BTCUSDT", "targetMarginType": "ISOLATED"})
let res = signed_request(reqwest::Method::POST, "/v2/futures/close-and-switch-margin",
    &[], Some(&json!({ "symbol": "BTCUSDT", "targetMarginType": "ISOLATED" }))).await?;
$res = signed_request('POST', '/v2/futures/close-and-switch-margin', [],
    ['symbol' => 'BTCUSDT', 'targetMarginType' => 'ISOLATED']);

POST /v2/futures/position-mode

Toggle account-wide position mode.

AuthAPI_KEY (TRADE)

Body

{ "positionMode": "ONE_WAY" }

positionMode is ONE_WAY or HEDGE. The change is account-wide; the venue rejects with 400 if any open position exists.

Response

{ "ok": true, "data": { "positionMode": "ONE_WAY" } }

Example

TS=$(($(date +%s) * 1000)); QUERY="timestamp=${TS}"
SIG=$(sign "$SECRET" "$QUERY")
curl -X POST -H "X-API-KEY: $API_KEY" -H "Content-Type: application/json" \
  -d '{"positionMode":"ONE_WAY"}' \
  "$BASE_URL/v2/futures/position-mode?${QUERY}&signature=${SIG}"
const res = await signedRequest('POST', '/v2/futures/position-mode', {
  body: { positionMode: 'ONE_WAY' },
});
res = signed_request("POST", "/v2/futures/position-mode",
    body={"positionMode": "ONE_WAY"}).json()
res, _ := zdex.SignedRequest("POST", "/v2/futures/position-mode", nil,
    map[string]any{"positionMode": "ONE_WAY"})
let res = signed_request(reqwest::Method::POST, "/v2/futures/position-mode",
    &[], Some(&json!({ "positionMode": "ONE_WAY" }))).await?;
$res = signed_request('POST', '/v2/futures/position-mode', [],
    ['positionMode' => 'ONE_WAY']);

On this page