useTrade
sdk.trading.
Place Orders
(pairId, side, quantity, price, options?) => Promise<CreateOrderResponse>
Place a limit order. Spot by default; opt into perp with
tradingMode: "MARGIN" and leverage.options:tradingMode?:"SPOT" | "MARGIN"useMasterBalance?: booleanexpirationDate?: string — ISO 8601; pair withGTCfor an order that expires at a set timetimeInForce?:"GTC" | "IOC" | "FOK"postOnly?: boolean — maker-only; the order is rejected instead of matching if it would cross the book.GTConly — rejected onMARKETorders and withIOC/FOK. See Post-Only OrdersselfTradePreventionMode?:"CANCEL_MAKER" | "CANCEL_TAKER" | "CANCEL_BOTH" | "SKIP"— how the engine resolves this order meeting one of your own resting orders (your whole wallet family). Overrides the wallet default; omit to inherit that, or the platform defaultCANCEL_MAKER. See Self-Trade Preventionleverage?: string — decimal string; required for normal margin orders, omit only for reduce-onlyreduceOnly?: boolean — order can only shrink existing exposuremarginAccountId?: string — optional legacy override; omit for normal perp orderspositionSide?:"LONG" | "SHORT" | "NONE"— deprecated.sideis the authoritative direction; if supplied,positionSidemust agree (BUY↔LONG,SELL↔SHORT)clientOrderId?: string — correlation handle echoed on order reads andordersWebSocket events (≤64 chars fromA-Za-z0-9._:-); not an idempotency key. Restate it onreplaceOrder— a replacement inherits nothing. See Client Order IDsidempotencyKey?: string — durable submission key. The SDK generates one for this call when omitted; retain and reuse an explicit key with the same payload to recover across calls or restarts within 15 minutes. See Safe Retries
side sets the direction. Attach TP/SL at entry with takeProfit/stopLoss (margin entry orders only; legs activate when the order fills), or attach to the open position with usePositions().attachPositionTpSl. A trailingStop leg attaches the same way, arms only when the order fully fills, and returns trailingStopOrderId only when the trailing stop materializes (a full fill on arrival or a resting remainder; a partial IOC / MARKET fill whose remainder is cancelled creates none) — see Trailing Stop.Perp example:(pairId, side, quantity, options?) => Promise<CreateOrderResponse>
Place a market order. Market orders execute inside a mandatory server-side price band, 1,000 bps by default (see Market-order price protection; a perp market can set its own) and can partially fill with the remainder cancelled, or be rejected when no liquidity sits inside the band.
options:tradingMode?:"SPOT" | "MARGIN"slippageTolerance?: number — tightens the market’s price band (e.g.0.01for 1%); cannot widen itleverage?: string — required for normal margin orders, omit only for reduce-onlyreduceOnly?: booleanmarginAccountId?: string — optional legacy override; omit for normal perp orderspositionSide?:"LONG" | "SHORT" | "NONE"— deprecated;sideis authoritativeclientOrderId?: string — correlation handle echoed on order reads andordersWebSocket events (≤64 chars fromA-Za-z0-9._:-); not an idempotency key. See Client Order IDsselfTradePreventionMode?:"CANCEL_MAKER" | "CANCEL_TAKER" | "CANCEL_BOTH" | "SKIP"— how the engine resolves this order meeting one of your own resting orders (your whole wallet family). Overrides the wallet default; omit to inherit that, or the platform defaultCANCEL_MAKER. See Self-Trade PreventionidempotencyKey?: string — durable submission key. The SDK generates one for this call when omitted; retain and reuse an explicit key with the same payload to recover across calls or restarts within 15 minutes. See Safe Retries
Order Management
(orderId) => Promise<CancelOrderResponse>
Cancel an existing order
(orderIds: string[]) => Promise<BatchCancelOrdersResponse>
Cancel specific orders by their IDs.Returns:
totalRequested: numbertotalCancelled: numbertotalFailed: numberresults:BatchCancelResult[]— each withorderId, optionalcancelledAt, optionalerror: { code, message }
results has one entry per requested ID, in request order, so totalRequested is always the number of IDs sent. An ID that is not one of your live orders fails with ORDER_NOT_FOUND. Use totalFailed === 0 for an overall-success check.Capped at 100 order IDs per request by the API (enforced server-side, no client-side schema check); a longer list is rejected with 400 At most 100 orders per batch request. batchCancelAll enumerates active orders server-side, with a separate cap of 20,000 matching active orders.Example:(tradingPairId?: string) => Promise<BatchCancelOrdersResponse>
Cancel all active orders, optionally scoped to one trading pair.The API caps the request at 20,000 matching active orders. Above that cap, it cancels nothing and returns REST
400; narrow by trading pair or cancel explicit batches of at most 100 IDs. The cap check is all-or-nothing and runs before any cancellation.Returns the same shape as batchCancel.Throws:- REST
400when the pair UUID is invalid or more than 20,000 matching active orders would be cancelled - REST
401when authentication is missing or invalid - REST
403when a delegated session omits the required pair scope or lacks permission - REST
500for an internal matching-engine failure - REST
503for a transient matching-engine or transport failure
(timeoutMs: number, options?: { tradingPairId?: string }) => Promise<CancelAllAfterResponse>
Arm, refresh or disarm the cancel-all-after dead man’s switch: unless you call again before
timeoutMs runs out, your resting orders are cancelled with terminalReason CANCEL_ALL_AFTER. 0 disarms; otherwise 5000 to 900000 ms. See cancelAllAfter for what is cancelled and the errors.Example:(orderId, newOrder) => Promise<ReplaceOrderResponse>
Modify an existing order’s price or quantity.
quantity is the order’s new total (a partially filled order rests total - filled and must exceed the filled amount; omit it to keep the total), and the replacement inherits the original’s fill history — see replaceOrder for the full semantics. newOrder also accepts postOnly, clientOrderId and selfTradePreventionMode — a replacement is a new order and inherits none of them, so restate clientOrderId to keep the handle and selfTradePreventionMode to keep the override. batchReplace items take the same three. See Client Order IDs.Batch Operations
(orders: BatchCreateOrderParams[]) => Promise<BatchCreateOrdersResponse>
Create multiple orders in a single request. Capped at 100 items — a longer array is rejected client-side (
At most 100 orders per batch request, exported as MAX_BATCH_ORDER_ITEMS) before the request is sent.BatchCreateOrderParams:tradingPairId: stringorderType:"LIMIT" | "MARKET"side:"BUY" | "SELL"quantity: stringprice?: string — required for LIMITtimeInForce?:"GTC" | "IOC" | "FOK"— LIMIT items only; the SDK rejects it on a MARKET item (market orders take no time-in-force and always execute IOC-style inside the price band)postOnly?: boolean — maker-only; the item is rejected instead of matching if it would cross the book, reported per-item aserror.code === "POST_ONLY_WOULD_CROSS". LIMIT items withGTConly. See Post-Only OrdersselfTradePreventionMode?:"CANCEL_MAKER" | "CANCEL_TAKER" | "CANCEL_BOTH" | "SKIP"— per-item self-trade-prevention override. The value is validated client-side, so an unknown mode throwsValidationErrorbefore the request is sent; the per-itemerror.codeINVALID_SELF_TRADE_PREVENTION_MODEis the raw REST/gRPC caller’s shape. See Self-Trade PreventionslippageTolerance?: number — for MARKETexpirationDate?: string — ISO 8601, custom expiry for GTCuseMasterBalance?: booleanclientOrderId?: string — per-item correlation handle echoed on order reads andordersWebSocket events (≤64 chars fromA-Za-z0-9._:-); a malformed value fails that item witherror.code === "INVALID_CLIENT_ORDER_ID". Not an idempotency key. See Client Order IDsidempotencyKey?: string — per-item durable submission key. The SDK generates one per item when omitted. Retain explicit per-item keys for recovery across calls; each key protects only its own item and does not make the batch atomic. See Safe Retries
BatchCreateOrdersResponse:totalRequested: numbertotalSucceeded: numbertotalFailed: numberresults:BatchCreateResult[]
BatchCreateResult:orderId: string — empty if creation failed before ID assignmentmatchResult?:MatchResult— present if order was immediately matchederror?:BatchError—{ code, message }. Treat absence oferroras success.
(orders: BatchReplaceOrderParams[]) => Promise<BatchReplaceOrdersResponse>
Replace multiple orders in a single request. Each replacement atomically cancels the original and creates a new one. Capped at 100 items — a longer array is rejected client-side (
At most 100 orders per batch request) before the request is sent.BatchReplaceOrderParams:orderId: stringprice?: stringquantity?: string — the order’s new total (same rule asreplaceOrder): a partially filled order reststotal - filledand the total must exceed the filled amount; omit it to keep the order’s total. Margin reduce-only orders follow the same rule, and the replacement inherits the original’s fill historyuseMasterBalance?: booleanclientOrderId?: string — per-item correlation handle for the replacement order (a replacement does not carry over the original’sclientOrderId, so restate it). A malformed handle fails its item alone (error.codeINVALID_CLIENT_ORDER_ID, the same code batch-create uses) with its original untouched. See Client Order IDspostOnly?: boolean — maker-only intent for the replacement; never inherited from the original. See Post-Only OrdersselfTradePreventionMode?:"CANCEL_MAKER" | "CANCEL_TAKER" | "CANCEL_BOTH" | "SKIP"— per-item self-trade-prevention override for the replacement, likewise never inherited; omit it to fall back to your wallet default. An unknown value is rejected client-side withValidationErrorbefore sending;error.codeINVALID_SELF_TRADE_PREVENTION_MODEis what a raw REST/gRPC caller gets on that item alone. See Self-Trade Prevention
BatchReplaceOrderItemSchema requires at least one of price or quantity, so an item carrying only selfTradePreventionMode (or only postOnly) throws ValidationError before the request is sent. Restate the price or quantity alongside the option.Returns — BatchReplaceOrdersResponse:totalRequested,totalSucceeded,totalFailed: numberresults:BatchReplaceResult[]
BatchReplaceResult:originalOrderId: stringnewOrderId?: stringupdatedFields?:{ price?, quantity? }matchResult?:MatchResulterror?:BatchError—{ code, message }. Absence oferrorindicates success.
Conditional Orders (Perp TP/SL)
Attach TP/SL and trailing stops at entry viatakeProfit/stopLoss/trailingStop on placeLimitOrder / placeMarketOrder, or to an open position with usePositions().attachPositionTpSl. The hook below covers listing and cancelling conditional orders. Concepts and lifecycle: Order Management.
(conditionalOrderId: string) => Promise<CancelConditionalOrderResponse>
Cancel an active conditional order.
(params?: ListConditionalOrdersParams) => Promise<ListConditionalOrdersResponse>
List conditional orders for the authenticated user. Passes
params straight to sdk.trading.listConditionalOrders, so cursor (pageToken) pagination is the default: follow each response’s nextPageToken until it comes back empty.Parameters:marginAccountId?,tradingPairId?,state?,pageToken?,pageSize?(up to1000)
Order Queries
(params?) => Promise<GetPaginatedOrdersResponse>
Fetch paginated orders
(orderId) => Promise<GetOrderResponse>
Get order details by ID
useUserOrders
New in v0.5.5 - Real-time order tracking with WebSocket updates
Parameters
number
default:50
Maximum number of orders to keep in state (configurable history limit)
Return Values
Order[]
Array of user orders, automatically updated in real-time. Merged from REST API initial data and WebSocket updates.A TWAP’s slices — the child orders a TWAP parent places, which carry
parentOrderId — are not in this list, from any source: the order listing leaves them to their parent, so the hook drops slice rows from the REST page, from the orders snapshot and from live frames alike. Read a TWAP’s slices with sdk.trading.listTwapOrderSlices.boolean
true while fetching initial orders from REST API, false once loadedboolean
true when WebSocket subscription is active, false otherwiseError | null
Error object if something went wrong during fetch or subscription,
null otherwise() => void
Function to clear the current error state
() => Promise<void>
Reconcile a fresh REST read with live orders, preserving newer live data received while the request was in flight. When the incoming row carries
version, the hook compares it first: it takes the REST row on incoming.version >= local.version and otherwise keeps local state. A versioned local row also wins over an unversioned response. Only when both sides lack version does the hook fall back to updatedAt; it retains live-only rows before applying the maxOrders limit.Features
Automatic Deduplication
Orders are automatically deduplicated by order ID. If the same order appears in both REST API response and WebSocket updates, only one copy is kept with the most recent data.Hybrid Data Loading
- Initial Load: fetches recent orders via REST (
getPaginatedOrders). - WebSocket Subscription: subscribes to the
orderschannel after the initial load. - Race Condition Prevention: the subscription only opens once the REST data is in, so an event cannot be overwritten by the response it raced.
- Subscribe-time Snapshot: the channel’s snapshot carries every resting order, and the hook reconciles it into the list.
Applying the snapshot
The snapshot lists persisted resting orders only, so it is not the whole list this hook shows. It reconciles rows it carries directly, while an omitted locally resting row needs a point read:- A snapshot row is ranked against the row already held on
version. It wins onsnapshot.version >= local.version; a lower or absent snapshot version cannot overwrite versioned local state left by the previous connection. When both versions are absent, the snapshot keeps its pre-counter precedence without comparing incompatible timestamps. - A row still showing
SUBMITTEDorPARTIALLY_FILLEDthat the snapshot omits is retained while the hook callssdk.trading.getOrder(orderId). Absence alone is ambiguous: the order may have filled or been cancelled during the outage, or persistence may lag a newer resting event the hook retained from the previous connection. Versioned results use the same ordering rule. When both rows are unversioned, the point result is accepted only if the held row did not change while the request was in flight; otherwise the hook preserves that intervening state and retries if it still needs resolution. - Terminal orders are untouched. The snapshot never carried them, so their absence says nothing.
selfTradePreventionMode is unreliable on this hook, as of v1.0.60. Rows seeded from REST carry it — the hook’s initial getPaginatedOrders load and its getOrder repairs both return it on Order. But orderFromEvent and orderFromSnapshotItem do not map it through, so a row that first appears from a live event or a subscribe-time snapshot omits it even though the underlying frame carries the value. Absence is therefore not evidence the order carried no override — unlike postOnly, where absence is meaningful. Where the requested mode matters, read it from sdk.trading.getOrder or the core sdk.ws.userOrders stream rather than from a row this hook built from stream data.
- A snapshot row is layered over the order it supersedes, not substituted for it, so fields the hook does not take from the row —
postOnly,expirationDate,positionSide,terminalReason,conditionalOrderIdand the fee aggregates — survive.
conditionalOrderId — the take-profit or stop-loss conditional that placed a triggered close — is REST-only in the strictest sense: no order event and no snapshot row carries it, so a close this connection saw first over the socket carries no value for it. The hook does not schedule a read just because the field is missing — an order added from an OrderPlaced event is not enqueued for repair, and snapshot reconciliation leaves terminal rows alone — so the field appears only when some REST read of that order happens anyway: your own refetch, or one of the hook’s existing repair reads. Absent on orders the user placed, and on closes written before the field existed.
origin says what placed an order: "USER", "LIQUIDATION", "ADL" or "SYSTEM". A liquidation is a reduce-only IOC limit order, so orderType, timeInForce and reduceOnly read the same as an order the user placed; render the row as a liquidation from origin === "LIQUIDATION". The hook takes it from the OrderPlaced acknowledgement, from every later order frame (fills, cancels, expiry), from every subscribe-time snapshot row and from every REST row, so an order the user placed reads "USER" from whichever arrives first. A frame only fills in a missing origin; it never replaces one the row already has. Because it never changes for an order, whichever side knows it supplies it: a row from a server that does not report it gains it on the next REST read, and a row that learned it from the socket keeps it against a REST row that does not report one. If both report one and they differ, the REST row is the stored order and its value stands. Absent means not reported, never "USER".
placementTakerFeeBps and placementMakerFeeBps are the Monaco fee rates fixed when the order was placed, in basis points. The hook takes them from the OrderPlaced acknowledgement, from subscribe-time snapshot rows and from REST rows. An order placed before rates were stored has neither, and absent never means "0".
The fee aggregates are the one thing that can go stale rather than missing, because they accumulate with fills. A snapshot reporting a fill this connection never saw schedules the same debounced REST re-read the hook already uses, which is their only source.
If a snapshot row carries a future enum value this SDK cannot render, its validated orderId still marks that order present. The hook schedules a broad compatibility re-read for that row while continuing targeted resolution for distinct locally resting orders the snapshot omitted.
The broad REST repair is debounced and page-limited, but snapshot omissions use targeted reads because an older order may no longer fit on the newest list page. Those reads are deduplicated across repeated snapshots, limited to four in flight, and applied as each one succeeds, so a slow order does not delay its siblings. Each attempt releases its queue slot after ten seconds. If a point read fails or times out, the hook keeps the local row rather than treating that as proof the order is terminal; a later snapshot can retry it.
Real-time Updates
The hook listens to all order events:OrderPlaced- New orders added to state. A new row starts atfilledQuantity: "0"with noaverageFillPrice, except the replacement of a partly filled order (an edit): it starts from the fill and average itsOrderPlacedcarries over from the original, asgetOrderreports itOrderPartiallyFilled- Order updated with fill amountOrderFilled- Order marked as fully filledOrderCancelled- Order marked as cancelledOrderRejected- Order marked as rejectedOrderExpired- Order marked as expired
Authentication Required
This hook requires an authenticated session. Log in with theuseAuth hook (or sdk.login(...)) before using it.
Basic Usage
Filter Active Orders
Group by Trading Pair
Order History with Filters
Real-time Order Updates
Error Handling with Retry
Complete Dashboard Example
Order Type Structure
See Also
- useTrade - Place, cancel, and manage orders
- useOrderbook - Real-time orderbook updates
- WebSocket API - Low-level userOrders WebSocket channel
- TypeScript SDK - Core SDK WebSocket methods
usePositions
sdk.positions. Each method is the same async function, ready to call from components or effects. There’s no state, subscriptions, or auto-refresh built in — wrap calls in your own useEffect / SWR / React Query as suits your app.
For end-to-end flow and UI patterns, see Positions.
Read
(params?: ListPositionsParams) => Promise<ListPositionsResponse>
Paginated list of positions.Parameters:
params?:marginAccountId?: stringtradingPairId?: stringstatus?:PositionStatusFilter—"OPEN" | "CLOSED" | "LIQUIDATING" | "LIQUIDATED"pageSize?: number — 1 to 1000, defaults to 20pageToken?: string — pagination cursor: omitted or""starts the walk; a previousnextPageTokenresumes it. There is nopage: the SDK rejects one with aValidationErrorbefore sending, and a raw REST request carrying it gets400
{ positions: Position[]; total: number; pageSize: number; nextPageToken: string; totalCapped: boolean }. Follow nextPageToken until it comes back ""; each page over-fetches one row, so an empty token is definitive.Example — positions panel:(positionId: string) => Promise<Position>
Full snapshot of a single position. Includes side, size, entry/mark/liquidation prices, isolated margin, leverage, and PnL. See
Position type.(positionId: string) => Promise<PositionRisk>
Volatile risk fields (mark price, liquidation price, margin ratio, unrealized PnL). Cheaper than
getPosition for live displays.Example — live liquidation distance:(params?: ListPositionHistoryParams) => Promise<ListPositionHistoryResponse>
Lifecycle events for one position or all positions in scope.Parameters:
params?:positionId?: stringmarginAccountId?: stringtradingPairId?: stringreductionOnly?: boolean — whentrue, returns only reductions, closes and liquidationspageSize?: number — 1 to 1000, defaults to 20pageToken?: string — pagination cursor: omitted or""starts the walk; a previousnextPageTokenresumes it. There is nopage: the SDK rejects one with aValidationErrorbefore sending, and a raw REST request carrying it gets400
{ events: PositionHistoryEvent[]; pageSize: number; nextPageToken: string }. This listing carries no total: the relation spans the archive, so it is not counted behind a filter.Modify
This hook has no margin-adjustment method. Adjust a position’s margin through the margin-account SDK surface — every leg
moves collateral between a risk bucket and the parent margin account, never to
or from the spot wallet:
transferCollateralToRiskBucketadds margin: by default it commits the amount to the open position’s stored margin (leverage drops and stays down); passapplyToPositionMargin: falseto fund the bucket with spendable free collateral instead. The pair-scopedtransferCollateralToMarginAccountis deprecated and matches the default.transferCollateralFromMarginAccount(withtradingPairId) releases collateral back to the parent.
(positionId, request) => Promise<AttachPositionTpSlResponse>
Attach take-profit and/or stop-loss conditional orders to the position. At least one leg is required. Pass
oco: true to cancel the sibling once one leg triggers (requires both legs).Parameters:positionId: stringrequest:takeProfit?:TpSlLegstopLoss?:TpSlLegtrailingStop?:TrailingStopLeg—{ trailBps, activationPrice?, closePosition?, quantity?, slippageToleranceBps?, expiresAt? }; one per position, never part ofoco. See Trailing Stopoco?: boolean — cancel the sibling leg after one triggers; requires both fixed legs
TpSlLeg: { triggerPrice, orderType: "MARKET" | "LIMIT", limitPrice?, closePosition?, quantity?, timeInForce?, slippageToleranceBps?, expiresAt? }. Set closePosition: true to resolve the full live position size on trigger (omit quantity). See Order Management.Example — TP/SL modal submit:Close
(positionId, request) => Promise<ClosePositionResponse>
Submit a closing order. Position transitions to
CLOSED only after the closing order fills.Parameters:positionId: stringrequest:closeType:"MARKET" | "LIMIT" | "IOC"limitPrice?: string — required forLIMITandIOC, forbidden only forMARKETquantity?: string — defaults to full position sizeslippageToleranceBps?: number — forMARKET/IOC
(request?: BatchCloseAllRequest) => Promise<BatchCloseAllResponse>
Submit a MARKET reduce-only close for every open position owned by the caller — a one-call “panic close”. Best-effort and partial: each position closes independently, and per-position failures are reported in
results instead of aborting the batch. See BatchCloseAllResponse type.Parameters:-
request?:tradingPairId?: string — limit the close to one trading pair. Cannot be combined withtradingPairIdstradingPairIds?: string[] — limit the close to any of these trading pairs (1 to 256), in one request. An empty array is rejected; omit the field to close every pairside?:"LONG" | "SHORT"— limit the close to one sideslippageToleranceBps?: number — applied to each MARKET close
Subscribing to lifecycle events
usePositions doesn’t ship a built-in subscription. For live updates of conditional-order lifecycle (TP/SL state changes), use sdk.ws.conditionalOrders — see the WebSocket reference.
For order-fill confirmations after a closePosition or attached-TP/SL trigger, subscribe to sdk.ws.userOrders.
