Adjust a Position
Grow or trim an open basket, whole or one leg at a time.
Growing a basket and trimming it are the same call: POST /trade/{positionId}/adjust (SDK: sdk.core.trade.adjust).
An adjust states the legs to change, not a percentage of the basket. Each leg carries reduceOnly, and that flag is what decides whether the leg grows or shrinks.
Add to a position
Give the leg's current side and reduceOnly: false. This adds 250 USD to each side of a long BTC / short ETH basket:
{
"type": "MARKET",
"legs": [
{ "symbol": "0", "side": "BUY", "mode": "USD", "amount": "250", "reduceOnly": false },
{ "symbol": "1", "side": "SELL", "mode": "USD", "amount": "250", "reduceOnly": false }
],
"clientId": "your-client-id"
}With the SDK:
await sdk.core.trade.adjust(positionId, {
type: 'MARKET',
legs: [
{ symbol: '0', side: 'BUY', mode: 'USD', amount: '250', reduceOnly: false },
{ symbol: '1', side: 'SELL', mode: 'USD', amount: '250', reduceOnly: false },
],
});clientId is optional. type accepts only "MARKET".
Trim a position
Give the opposite side and reduceOnly: true, so a long BTC leg is reduced by selling. This takes 200 USD off each side and leaves the rest open:
{
"type": "MARKET",
"legs": [
{ "symbol": "0", "side": "SELL", "mode": "USD", "amount": "200", "reduceOnly": true },
{ "symbol": "1", "side": "BUY", "mode": "USD", "amount": "200", "reduceOnly": true }
]
}reduceOnly passes through to the exchange's reduce-only flag, which stops the order growing the leg or flipping it past flat.
The leg fields
| Field | Type | Meaning |
|---|---|---|
symbol | string | The instrument ID, not the ticker. |
side | BUY or SELL | The direction to trade in, not the direction the leg currently holds. |
mode | QUANTITY or USD | How to read amount. |
amount | decimal string | Always unsigned, so "250", never "-250". The direction lives in side and reduceOnly. |
reduceOnly | boolean | Required on every leg. |
One leg at a time
Nothing requires you to touch every leg. Adjusting one leg alone is valid, and changes the basket's weights:
{
"type": "MARKET",
"legs": [
{ "symbol": "0", "side": "SELL", "mode": "USD", "amount": "200", "reduceOnly": true }
]
}To restore the target shares afterwards, rebalance the position.
An adjust can add a leg the basket does not hold
An adjust does not check that symbol is already in the position. Naming an instrument the basket does not hold grows the basket by that leg: a two-leg pair becomes a three-leg basket, and stays that way.
That is a supported way to build out a basket, and an easy typo to make. If you meant to change an existing leg, check the symbol against the position's exposure before you send it.
An adjust pauses auto-rebalance
An adjust that fills at all pauses the position's auto-rebalance config, with pausedReason: "POSITION_CHANGED". The config stops evaluating and does not rebalance until you resume it with PATCH /rebalance/auto/{id}:
{ "status": "ACTIVE" }Resume keeps the existing baseline. A rebalance the config performs itself never pauses it — only changes you make do.
Rules
- At least one leg, and each leg names a distinct instrument.
- A reduce cannot flip a leg. To go the other way, either close and reopen, or use
POST /trade/{positionId}/reverse, which flips every leg in one call. - The position must be
OPEN. Adjusting anything else returns 409.
Two checks apply only to legs that add size, never to a reduceOnly leg:
| Check | Rejected with |
|---|---|
| The leg is too small for the instrument's minimum order size | Insufficient size for asset |
| The leg sells a spot instrument | Short selling is not supported for spot markets |
A reducing leg skips both, which is what lets you close out a leg that has shrunk below the minimum.
Adjust on a condition
To scale into a position when the market moves rather than now, arm an open trigger against the position: POST /triggers/open with intent: "ADJUST", a positionId, a condition, and the legs to add. It rests off-book and increases the position when the condition is met. See Trigger Order.
The response
The endpoint answers 202 with an execution, and the change lands over the WebSocket as position.updated. When a reduce takes the basket to zero, the position closes and you get position.closed with closedReason: "USER".