cTrader APITrading

For AI agents: this page is also available as Markdown at /docs/ctrader/trading.md. The index of every docs page is /docs/llms.txt.

cTrader Trading API

Place, modify, and close cTrader orders over a REST API: market and pending orders, partial closes, plus margin and profit calculators for position sizing. Orders go to cTrader through Spotware's Open API, and the replies use MT5's retcodes, so one client trades MetaTrader and cTrader accounts alike.

How trading works on cTrader

  • Six order types. Market, limit and stop, each as buy or sell. BuyStopLimit and SellStopLimit are refused with 400 MRPC_VALIDATION, since cTrader's stop-limit fills within a range beyond the stop rather than resting as a limit order at stopLimitPrice the way MT5's does.
  • Netting changes what an opposite order does. On a netting account an opposite order reduces, closes or reverses the position instead of opening a second one, as on MT5. Check marginMode in /AccountInfo.
  • Stops on market orders. cTrader takes a market order's stop loss and take profit as distances from the fill. The bridge sends them from the current price and, if the fill slipped, sets your exact levels right after; a modify event on the trades topic follows.
  • Checked before sending. A volume off the symbol's volumeStep (10014), a pending price on the wrong side of the market (10015) and a modify that changes nothing (10025) are answered by the bridge, the way MT5 would answer them, without a request to cTrader.
  • MT5's retcodes. cTrader's own error codes are translated into MT5 retcodes, with cTrader's message in comment, so your code branches on the same numbers for every platform. cTrader errors and their retcodes
  • Retries without double fills. Send orders with a clientOrderId and a retry with the same id never trades twice. When an answer gets lost, the bridge looks the order up by its id before it reports MRPC_TRADE_OUTCOME_UNKNOWN. All error codes
  • One change per ticket at a time. Requests for different tickets run side by side; two for the same ticket run one after the other.
  • No manual execution. execution: "Manual" is a MetaTrader workaround and is refused; cTrader orders always go through the Open API.

Orders go to cTrader through the Open API. A 200 response only means cTrader returned a result; always inspect success and retcode to confirm the broker accepted it. Every trade reply also carries position (the position the request opened or acted on), time and timeUtc of the fill (empty when nothing filled, such as a modify or a newly placed pending order), and a Server-Timing header: queue is how long the request waited for the account's trade engine, exec how long it took there and at cTrader, both in milliseconds.

POST /ctrader/{account_id}/OrderSend

Submit a market or pending order. Market (Buy/Sell) needs symbol + volume; price is ignored. Pending (*Limit/*Stop) additionally needs price, on the right side of the market (a buy stop above the ask, a buy limit below it), or the order is refused with 10015 before it is sent. Volume must be a multiple of the symbol's volumeStep (10014 otherwise). Optional: stopLoss, takeProfit, an expiry for pending orders (expiration or expirationUtc, both UTC, not both; absent → good-till-cancelled), comment, expertId (a.k.a. magic), and clientOrderId. slippage is accepted and ignored. With a clientOrderId a retry is safe: the first request with an id trades, and any repeat with the same id, whether it overlaps the first or comes up to 10 minutes later, trades nothing and gets the first request's reply with the header Idempotent-Replayed: true. Reusing an id for a different order is refused with 409 MRPC_CLIENT_ORDER_ID_REUSED.

  • symbol (required): Symbol to trade, e.g. EURUSD.
  • operation (required): Buy, Sell, BuyLimit, SellLimit, BuyStop, SellStop (case- and separator-insensitive). BuyStopLimit and SellStopLimit are refused, see below.
  • volume (required): Volume in lots.
  • price: Required for pending orders; ignored for market orders.
  • stopLoss / takeProfit: Optional SL/TP prices.
  • expiration: Pending-order expiry (date string, UTC); absent → good-till-cancelled.
  • expirationUtc: The same as ISO-8601 such as 2026-11-03T17:00:00Z; use instead of expiration.
  • comment / expertId: Order comment and magic number.
  • clientOrderId: Your own id for this order, 1–64 characters, remembered for 10 minutes. Echoed in the reply.
Request body
{
  "symbol": "EURUSD",
  "operation": "Buy",
  "volume": 0.01,
  "stopLoss": 1.11000,
  "takeProfit": 1.12500,
  "comment": "my-strategy",
  "expertId": 26111001,
  "clientOrderId": "copy-7f3a-0001"
}
Example request
curl -X POST https://api.fxsocket.com/ctrader/{account_id}/OrderSend \
  -H "X-API-Key: fxs_live_..." \
  -H "Content-Type: application/json" \
  -d '{"symbol":"EURUSD","operation":"Buy","volume":0.01,"stopLoss":1.11,"takeProfit":1.125,"comment":"my-strategy","expertId":26111001,"clientOrderId":"copy-7f3a-0001"}'
Response
{
  "success": true,
  "outcome": "applied",
  "retcode": 10009,
  "retcodeDescription": "Done",
  "deal": 343051307,
  "order": 328018035,
  "volume": 0.01,
  "price": 1.11685,
  "bid": 1.11662,
  "ask": 1.11685,
  "comment": "",
  "position": 302262716,
  "time": "2026-11-10T22:38:46.909Z",
  "timeUtc": "2026-11-10T22:38:46.909Z",
  "remainderTicket": 0,
  "clientOrderId": "copy-7f3a-0001"
}
POST /ctrader/{account_id}/OrderModify

Modify an existing position or pending order. The ticket type decides what's modifiable: a position ticket accepts only stopLoss and takeProfit; a pending-order ticket also accepts price and expiration. Omit a field to keep its current value. A modify that changes nothing answers retcode 10025 (No changes) with outcome no_change, without a request to cTrader.

  • ticket (required): Position or pending-order ticket.
  • stopLoss / takeProfit: New SL/TP; omit to keep current.
  • price: New price (pending orders only).
  • expiration: New expiration (date string, UTC), pending orders only.
  • expirationUtc: The same as ISO-8601, instead of expiration.
Request body
{
  "ticket": 302262716,
  "stopLoss": 1.11000,
  "takeProfit": 1.12500
}
Example request
curl -X POST https://api.fxsocket.com/ctrader/{account_id}/OrderModify \
  -H "X-API-Key: fxs_live_..." \
  -H "Content-Type: application/json" \
  -d '{"ticket":302262716,"stopLoss":1.11,"takeProfit":1.125}'
Response
{
  "success": true,
  "outcome": "applied",
  "retcode": 10009,
  "retcodeDescription": "Done",
  "deal": 0,
  "order": 0,
  "volume": 0.0,
  "price": 0.0,
  "bid": 1.11662,
  "ask": 1.11685,
  "comment": "",
  "position": 302262716,
  "time": "",
  "remainderTicket": 0
}
POST /ctrader/{account_id}/OrderClose

Close a position or delete a pending order: the action is inferred from the ticket type. For a position, supply volume for a partial close (must respect the symbol's volumeStep) or omit it for a full close. For a pending order, volume is ignored and the order is deleted. A position keeps its ticket through a partial close, so remainderTicket is always 0 on cTrader.

  • ticket (required): Position ticket (closes it) or pending-order ticket (deletes it).
  • volume: Partial close volume; omit or 0 = full close.
Request body
{
  "ticket": 302262716
}
Example request
curl -X POST https://api.fxsocket.com/ctrader/{account_id}/OrderClose \
  -H "X-API-Key: fxs_live_..." \
  -H "Content-Type: application/json" \
  -d '{"ticket":302262716}'
Response
{
  "success": true,
  "outcome": "applied",
  "retcode": 10009,
  "retcodeDescription": "Done",
  "deal": 343051320,
  "order": 328018048,
  "volume": 0.01,
  "price": 1.11662,
  "bid": 1.11662,
  "ask": 1.11685,
  "comment": "",
  "position": 302262716,
  "time": "2026-11-10T22:38:51.590Z",
  "timeUtc": "2026-11-10T22:38:51.590Z",
  "remainderTicket": 0
}
GET /ctrader/{account_id}/OrderCalcMargin

Margin a hypothetical order would need, in the account currency. cTrader computes it at the current price; the bridge moves it to the price you pass: on an account in the symbol's quote currency, and for CFDs and indices, the margin follows the price, on an account in the base currency or a third one it does not depend on it. With tiered leverage the result is an approximation. Does not place an order, purely a sizing/risk query.

  • symbol (required): Symbol name as listed by /symbols.
  • operation (required): Buy, Sell, BuyLimit, SellLimit, BuyStop, SellStop.
  • volume (required): Volume in lots.
  • price (required): Hypothetical entry price.
Example request
curl -H "X-API-Key: fxs_live_..." \
  "https://api.fxsocket.com/ctrader/{account_id}/OrderCalcMargin?symbol=EURUSD&operation=Buy&volume=0.1&price=1.11685"
Response
{
  "symbol": "EURUSD",
  "operation": "Buy",
  "volume": 0.1,
  "price": 1.1,
  "margin": 100.0,
  "currency": "EUR"
}
GET /ctrader/{account_id}/OrderCalcProfit

Projected P&L for a hypothetical open → close move, in the account currency, converted at the current rate. Computed by the bridge from the symbol's contract size and cTrader's conversion rates. Does not place an order, useful for position sizing and UI.

  • symbol (required): Symbol name as listed by /symbols.
  • operation (required): Buy or Sell (pending variants accepted, only the direction is used).
  • volume (required): Volume in lots.
  • priceOpen (required): Hypothetical open price.
  • priceClose (required): Hypothetical close price.
Example request
curl -H "X-API-Key: fxs_live_..." \
  "https://api.fxsocket.com/ctrader/{account_id}/OrderCalcProfit?symbol=EURUSD&operation=Buy&volume=0.1&priceOpen=1.11685&priceClose=1.12685"
Response
{
  "symbol": "EURUSD",
  "operation": "Buy",
  "volume": 0.1,
  "priceOpen": 1.1,
  "priceClose": 1.11,
  "profit": 89.56,
  "currency": "EUR"
}