Orders

Order types, time-in-force policies, and execution flags

This guide covers OBSDN order types, execution behavior, time-in-force policies, and order flags.

The JSON examples below show the wire fields used by POST /orders (PlaceOrderRequest). Required fields like mkt_id, nonce, and sig are omitted from each example for brevity, see Getting Started for the full payload.

Two wire-format rules apply throughout:

  • Enums use the full proto name. Send ORDER_SIDE_BUY, not BUY; short forms are rejected.
  • uint64/int64 fields are JSON strings. nonce, exp_ts, and sched_ts exceed JavaScript's safe integer range, so they're quoted on the wire.

Wire Field Reference

FieldTypeDescription
mkt_idstringMarket identifier (e.g., BTC-PERP)
sdenumSide: ORDER_SIDE_BUY, ORDER_SIDE_SELL
otenumOrder type: ORDER_TYPE_LIMIT, ORDER_TYPE_MARKET, ORDER_TYPE_STOP, ORDER_TYPE_TWAP
szstringDecimal size in base asset units
pxstringDecimal limit price in quote asset units
tifenumTime-in-force: TIME_IN_FORCE_GTC, TIME_IN_FORCE_IOC, TIME_IN_FORCE_FOK, TIME_IN_FORCE_GTT
poboolPost-only
roboolReduce-only
stpenumSelf-trade prevention: SELF_TRADE_PREVENTION_CANCEL_TAKER, SELF_TRADE_PREVENTION_CANCEL_MAKER, SELF_TRADE_PREVENTION_CANCEL_BOTH
cl_oidstringClient-assigned order id (max 32 chars; alphanumeric + -_:)
noncestring (uint64)Unix nanoseconds; included in the EIP-712 payload. Must be within ±5 minutes of server time; otherwise the request returns 400 nonce too far from current timestamp.
sigstringEIP-712 signature from the registered signer
stop_tenumStop subtype: STOP_TYPE_STOP_LOSS, STOP_TYPE_TAKE_PROFIT (STOP only)
stop_pxstringDecimal trigger price (STOP only)
stop_px_typeenumTrigger source: STOP_PRICE_TYPE_LAST, STOP_PRICE_TYPE_MARK (STOP only)
exp_tsstring (uint64)Expiration timestamp in nanoseconds (GTT only)
sched_tsstring (int64)Scheduled execution timestamp in nanoseconds (TWAP sub-orders only; ignored for other types)
awaitboolWait for matching engine confirmation (MARKET/LIMIT only)

Defaults when fields are omitted

FieldDefaultNotes
otORDER_TYPE_LIMIT
tifTIME_IN_FORCE_GTC
stpSELF_TRADE_PREVENTION_CANCEL_TAKEROmitting stp does not disable self-trade prevention
stop_px_typeSTOP_PRICE_TYPE_LAST

Order Types

LIMIT

A limit order rests on the order book at a specified price until filled or canceled.

{
  "ot": "ORDER_TYPE_LIMIT",
  "sd": "ORDER_SIDE_BUY",
  "px": "50000",
  "sz": "0.1",
  "tif": "TIME_IN_FORCE_GTC"
}
  • Execution: only fills at the specified price or better
  • Book: rests on the order book if not immediately filled
  • Use case: when you want to control execution price

MARKET

A market order executes immediately at the best available price.

{
  "ot": "ORDER_TYPE_MARKET",
  "sd": "ORDER_SIDE_BUY",
  "px": "50000",
  "sz": "0.1",
  "tif": "TIME_IN_FORCE_IOC"
}
  • Execution: fills immediately against resting orders
  • Book: never rests on the order book
  • px: required; acts as a slippage cap: a buy will not match makers priced above it, a sell will not match makers priced below it
  • tif: must be TIME_IN_FORCE_FOK or TIME_IN_FORCE_IOC; GTC and GTT are not permitted
  • po: not permitted
  • Use case: when speed of execution matters more than price
Market orders may experience slippage in low liquidity conditions.

STOP

A stop order activates when the trigger price is reached.

{
  "ot": "ORDER_TYPE_STOP",
  "sd": "ORDER_SIDE_SELL",
  "px": "49000",
  "sz": "0.1",
  "stop_px": "49500",
  "stop_t": "STOP_TYPE_STOP_LOSS",
  "stop_px_type": "STOP_PRICE_TYPE_MARK"
}
FieldDescription
stop_pxPrice that activates the order
stop_tSTOP_TYPE_STOP_LOSS or STOP_TYPE_TAKE_PROFIT
stop_px_typeSTOP_PRICE_TYPE_LAST or STOP_PRICE_TYPE_MARK

Stop Subtypes

ValueTrigger Condition
STOP_TYPE_STOP_LOSSTriggers when price moves against your position
STOP_TYPE_TAKE_PROFITTriggers when price moves in your favor

Trigger Sources

ValueDescription
STOP_PRICE_TYPE_LASTTriggered by the last traded price
STOP_PRICE_TYPE_MARKTriggered by mark price

When stop_px_type is omitted (or STOP_PRICE_TYPE_UNSPECIFIED), last price is used.

TWAP (Algorithmic)

TWAP time-slices a parent order across scheduled sub-orders. Submit TWAP batches via POST /orders/twap: mkt_id, sd, stp, and ro come from the batch envelope; each sub-order in sub_ords is individually signed and carries its own px, sz, nonce, sig, and sched_ts.

  • Execution: splits execution over time instead of taking full size at once
  • Use case: large orders where minimizing market impact matters more than immediate completion
{
  "mkt_id": "BTC-PERP",
  "sd": "ORDER_SIDE_BUY",
  "stp": "SELF_TRADE_PREVENTION_CANCEL_TAKER",
  "ro": false,
  "sub_ords": [
    {
      "px": "50000",
      "sz": "0.1",
      "nonce": "1700000000000000000",
      "sig": "0x...",
      "sched_ts": "1700000060000000000"
    },
    {
      "px": "50000",
      "sz": "0.1",
      "nonce": "1700000000000000001",
      "sig": "0x...",
      "sched_ts": "1700000120000000000"
    }
  ]
}

Batch validation rules (any violation returns 400):

  • All sub-orders must share the same px and sz (uniform slicing).
  • nonce values must be strictly increasing across the batch.
  • sched_ts intervals between consecutive sub-orders must be positive, equal, and divisible by 60 seconds.
  • The first sched_ts must be at least 10 seconds in the future.
  • At most 100 sub-orders per batch.
  • At most 200 untriggered conditional orders per market (shared with STOP orders); exceeding this returns 400.
  • Aggregate margin for the batch is checked up front; if the account cannot cover it, the entire batch is rejected.
  • If the account is currently in liquidation, the batch is rejected.
  • Reduce-only batches are validated against the current position side; wrong-side batches are rejected.
  • An empty sub_ords array returns 400 sub orders cannot be empty.

Time-in-Force (TIF)

Time-in-force determines how long an order remains active.

GTC (Good Til Canceled)

Order remains active until fully filled or manually canceled.

{ "tif": "TIME_IN_FORCE_GTC" }
  • Default behavior for most orders
  • Order stays on the book indefinitely

IOC (Immediate or Cancel)

Fills as much as possible immediately, cancels the rest.

{ "tif": "TIME_IN_FORCE_IOC" }
  • Partial fills allowed
  • Unfilled portion is immediately canceled
  • Use case: fill what you can now, don't leave orders on book

FOK (Fill or Kill)

Must fill entirely or not at all.

{ "tif": "TIME_IN_FORCE_FOK" }
  • No partial fills
  • Use case: all-or-nothing execution required

GTT (Good Til Time)

Order expires at a specified time.

{
  "tif": "TIME_IN_FORCE_GTT",
  "exp_ts": "1735689600000000000"
}
  • exp_ts is Unix nanoseconds, sent as a JSON string
  • Must be in the future and at most 30 days from now (otherwise the request is rejected)
  • Order is canceled automatically at the expiration time

Timing Controls

  • sched_ts: scheduled activation time in nanoseconds (TWAP sub-orders only). Ignored for other order types.
  • exp_ts: expiration time in nanoseconds (GTT only)
  • await: synchronous processing flag for MARKET/LIMIT submissions; the request waits for matching-engine processing before returning

Example (GTT limit order with synchronous submit):

{
  "ot": "ORDER_TYPE_LIMIT",
  "sd": "ORDER_SIDE_BUY",
  "px": "50000",
  "sz": "0.1",
  "tif": "TIME_IN_FORCE_GTT",
  "exp_ts": "1735689600000000000",
  "await": true
}

Special Flags

ro (reduce-only)

Only reduces an existing position, never increases it.

{ "ro": true }
  • Order canceled (returned as ORDER_STATUS_DONE with the corresponding done_rsn) if it would open or increase a position
  • Use case: closing positions without risk of accidental reversal

po (post-only)

Order must rest on the book (be a maker), never take liquidity.

{ "po": true }
  • Order canceled (returned as ORDER_STATUS_DONE with done_rsn canceled: post-only) if it would immediately match
  • Guarantees maker fee
  • Use case: market making, fee optimization

stp (Self-Trade Prevention)

Prevents your orders from matching against each other.

{ "stp": "SELF_TRADE_PREVENTION_CANCEL_TAKER" }
ValueBehavior
SELF_TRADE_PREVENTION_CANCEL_TAKERCancel the incoming (taker) order
SELF_TRADE_PREVENTION_CANCEL_MAKERCancel the resting (maker) order
SELF_TRADE_PREVENTION_CANCEL_BOTHCancel both orders

When stp is omitted or sent as SELF_TRADE_PREVENTION_UNSPECIFIED, the engine applies SELF_TRADE_PREVENTION_CANCEL_TAKER, STP cannot be disabled.

Use case: prevent self-matches when running multiple bots or accounts.

Order Status Lifecycle

LIMIT / MARKET

  PENDING -----------> OPEN -----------> DONE
  |                                    ^
  +------------------------------------+

STOP / TWAP

  UNTRIGGERED ------> OPEN -----------> DONE
  |                   |                ^
  |                   +----------------+
  +------------------------------------+

MARKET orders always transition directly from PENDING to DONE (they never rest on the book as OPEN). STOP and TWAP orders begin in UNTRIGGERED and move to OPEN only when triggered or scheduled; they can also go directly to DONE if canceled while untriggered.

Partial fills are not a separate status: filled_sz updates while the order remains OPEN. The order moves to DONE when fully filled or canceled.

StatusDescription
ORDER_STATUS_PENDINGLIMIT/MARKET order submitted, awaiting matching engine processing
ORDER_STATUS_OPENActive on the order book
ORDER_STATUS_UNTRIGGEREDConditional order waiting for trigger (STOP) or scheduled time (TWAP)
ORDER_STATUS_DONETerminal state: fully filled or canceled

Done Reasons

When an order reaches ORDER_STATUS_DONE, the done_rsn field carries the terminal reason:

done_rsnCause
filledOrder fully executed
canceled: userCanceled by the user
canceled: adminCanceled by an admin
canceled: post-onlyPost-only order would have crossed the book
canceled: insufficient liquidityNo matching orders on the opposite side
canceled: insufficient marginPortfolio under-margined after matching
canceled: time in force IOCUnfilled remainder after IOC matching
canceled: time in force FOKOrder not fully filled; entire order voided
canceled: time in force GTTOrder expired at exp_ts
canceled: stpSelf-trade prevention triggered
canceled: too many matchesExceeded 1,000 matches per order
canceled: reduce-only position already closedNo open position at pre-match time
canceled: reduce-only invalid side (...)Order side matches position side
canceled: reduce-only invalid size (...)Order size exceeds position size
canceled: reduce-only exceeds pos (...)Reduce-only non-IOC order whose size exceeds the open position. IOC reduce-only orders that exceed the position are clipped to position size and continue matching instead of being canceled.
canceled: reduce-only auto canceled due to position reductionResting reduce-only order excess after position reduced
canceled: tpsl position closedParent position closed before stop order triggered
canceled: parent order canceled unfilledParent order (bracket) canceled before fill
canceled: liquidationCanceled by liquidation engine
canceled: adl counterparty has no entry priceADL counterparty missing entry price
canceled: adl counterparty unprofitableADL counterparty not profitable enough
canceled: otc counter order reduce-only invalid sideOTC counter order side conflicts with position
canceled: otc counter order reduce-only invalid sizeOTC counter order size exceeds position
canceled: otc counter party insufficient marginOTC counterparty lacks margin for the trade

Bracket Orders

Create a parent entry order with linked take-profit and/or stop-loss children:

POST /orders/group
{
  "grp_t": "ORDER_GROUP_TYPE_BRACKET",
  "ords": [
    {
      "mkt_id": "BTC-PERP",
      "ot": "ORDER_TYPE_LIMIT",
      "sd": "ORDER_SIDE_BUY",
      "px": "50000",
      "sz": "0.1",
      "nonce": "1700000000000000000",
      "sig": "0x..."
    },
    {
      "mkt_id": "BTC-PERP",
      "ot": "ORDER_TYPE_STOP",
      "sd": "ORDER_SIDE_SELL",
      "px": "52500",
      "stop_px": "52000",
      "stop_t": "STOP_TYPE_TAKE_PROFIT",
      "sz": "0.1",
      "ro": true,
      "tif": "TIME_IN_FORCE_IOC",
      "nonce": "1700000000000000001",
      "sig": "0x..."
    },
    {
      "mkt_id": "BTC-PERP",
      "ot": "ORDER_TYPE_STOP",
      "sd": "ORDER_SIDE_SELL",
      "px": "47500",
      "stop_px": "48000",
      "stop_t": "STOP_TYPE_STOP_LOSS",
      "sz": "0.1",
      "ro": true,
      "tif": "TIME_IN_FORCE_IOC",
      "nonce": "1700000000000000002",
      "sig": "0x..."
    }
  ],
  "await": false
}

When the parent fills, the children transition from ORDER_STATUS_UNTRIGGERED to ORDER_STATUS_OPEN. When one child triggers and fills, the other is automatically canceled.

Set await: true to block the response until the parent has been processed by the matching engine (only effective when the parent is ORDER_TYPE_MARKET or ORDER_TYPE_LIMIT).

Bracket validation rules

The backend rejects the request if any of these are violated:

Rule
Order countexactly 2 or 3 (parent + 1–2 children)
Parent otORDER_TYPE_LIMIT, ORDER_TYPE_MARKET, or ORDER_TYPE_STOP
Parent romust be false (or omitted)
Children otmust be ORDER_TYPE_STOP
Children count by stop_tat most one STOP_TYPE_TAKE_PROFIT and one STOP_TYPE_STOP_LOSS
Children mkt_idsame as parent
Children szsame as parent
Children sdopposite of parent
Children romust be true
Children tifmust be TIME_IN_FORCE_IOC
TP stop_pxfor ORDER_SIDE_BUY parent: above parent px; for ORDER_SIDE_SELL parent: below parent px
SL stop_pxfor ORDER_SIDE_BUY parent: below parent px; for ORDER_SIDE_SELL parent: above parent px

Order Sides

ValueDescription
ORDER_SIDE_BUYLong / buying the asset
ORDER_SIDE_SELLShort / selling the asset

Examples

Limit Buy with Post-Only

{
  "ot": "ORDER_TYPE_LIMIT",
  "sd": "ORDER_SIDE_BUY",
  "px": "50000",
  "sz": "0.1",
  "tif": "TIME_IN_FORCE_GTC",
  "po": true
}

Stop-Loss to Close Long Position

{
  "ot": "ORDER_TYPE_STOP",
  "sd": "ORDER_SIDE_SELL",
  "px": "48000",
  "sz": "0.1",
  "stop_px": "48500",
  "stop_t": "STOP_TYPE_STOP_LOSS",
  "stop_px_type": "STOP_PRICE_TYPE_MARK",
  "ro": true
}

Market Order with IOC

{
  "ot": "ORDER_TYPE_MARKET",
  "sd": "ORDER_SIDE_BUY",
  "px": "50000",
  "sz": "0.1",
  "tif": "TIME_IN_FORCE_IOC"
}

Per-Market Order Limits

Each account is subject to the following order limits per market:

CategoryLimit
Pending orders200
Open (resting) orders200
Conditional (stop/TWAP) orders200

When a limit is reached, new orders for that market are rejected with maximum pending orders (200) reached for {market} (or the equivalent message for open/conditional orders). Cancel existing orders or wait for fills before placing new ones.

Next Steps

On this page