# New order (TRADE)

## API Description

Opens a market position or places a pending order.

## HTTP Request

```http
POST /v1/order
```

## Request Weight

1 (1 against `ORDERS`)

## Request Parameters

| Name | Type | Mandatory | Description |
| - | - | - | - |
| `login` | LONG | YES | MT5 account. |
| `symbol` | STRING | YES | Exact, case-sensitive. |
| `type` | ENUM | YES | `MARKET`, `BUY_LIMIT`, `SELL_LIMIT`, `BUY_STOP`, `SELL_STOP`, `BUY_STOP_LIMIT`, `SELL_STOP_LIMIT`. |
| `side` | ENUM | conditional | `BUY` or `SELL`. Mandatory for `MARKET`. For every pending type the side is implied by the type; if sent it must agree, otherwise `-1117`. |
| `volume` | DECIMAL | YES | Lots. Must be greater than `0` (`-4003`) and satisfy `volumeMin` (`-4006`), `volumeMax` (`-4005`) and `volumeStep` (`-4007`). |
| `price` | DECIMAL | conditional | Mandatory for every pending type, greater than `0` (`-4001`). Ignored for `MARKET` — a market order always fills at the server's price. |
| `stopLimitPrice` | DECIMAL | conditional | Mandatory for `BUY_STOP_LIMIT` and `SELL_STOP_LIMIT`: the limit price the order is placed at once `price` is touched. Sending it with any other `type` is `-1106`. |
| `sl` | DECIMAL | NO | Stop loss. `0` or omitted means none. Negative is `-4001`. |
| `tp` | DECIMAL | NO | Take profit. `0` or omitted means none. Negative is `-4001`. |
| `timeInForce` | ENUM | NO | Pending orders only — sending it on `MARKET` is `-1106`. `GTC` (default), `DAY`, `GTD`, `GTD_DAY`. Must be in the symbol's `expirationModes` (`-4012`). |
| `expiration` | LONG | conditional | Mandatory for `GTD` and `GTD_DAY` (`-1102`). Unix ms, greater than `0` (`-4012`). |
| `newClientOrderId` | STRING | NO | **Idempotency key.** Up to 36 characters, `[A-Za-z0-9-_.]` (`-1119` otherwise), unique per key. Strongly recommended. |
| `newOrderRespType` | ENUM | NO | `ACK` (default) or `RESULT`. |
| `comment` | STRING | NO | Up to **24** characters (`-1130` if longer). Stored on the MT5 order and deal and visible to the broker and the account holder. The service appends a short correlation tag of its own, so the comment you see back on a deal is longer than the one you sent — see [Comments and deal attribution](/trade.md#comments-and-deal-attribution). Not a substitute for `newClientOrderId`. |
| `recvWindow` | LONG | NO | Default `5000`, max `60000`. |
| `timestamp` | LONG | YES | |
| `signature` | STRING | YES | |

**Mandatory parameters by type**

| `type` | Mandatory |
| - | - |
| `MARKET` | `login`, `symbol`, `type`, `side`, `volume` |
| `BUY_LIMIT`, `SELL_LIMIT` | `login`, `symbol`, `type`, `volume`, `price` |
| `BUY_STOP`, `SELL_STOP` | `login`, `symbol`, `type`, `volume`, `price` |
| `BUY_STOP_LIMIT`, `SELL_STOP_LIMIT` | `login`, `symbol`, `type`, `volume`, `price`, `stopLimitPrice` |

Additionally, `expiration` is mandatory whenever `timeInForce` is `GTD` or `GTD_DAY`.

**Price rules**

| Type | `price` must be |
| - | - |
| `BUY_LIMIT` | below the current ask |
| `SELL_LIMIT` | above the current bid |
| `BUY_STOP` | above the current ask |
| `SELL_STOP` | below the current bid |
| `BUY_STOP_LIMIT` | above the current ask; `stopLimitPrice` is the resulting buy-limit price |
| `SELL_STOP_LIMIT` | below the current bid; `stopLimitPrice` is the resulting sell-limit price |

Violating these is `-2021`. Every price (`price`, `stopLimitPrice`, `sl`, `tp`) must be a multiple of
`tickSize` (`-4008`), and must keep `stopsLevel` points of distance (`-4009`) from the price MT5
measures it against:

- a pending order's `price` — from the market on its opening side (ask for a buy, bid for a sell);
- `sl` / `tp` on a **market** order — from the market on its closing side (bid for a buy, ask for a sell);
- `sl` / `tp` on a **pending** order — from the price the order will open at (`stopLimitPrice` for a
  stop-limit, `price` otherwise), not from the market.

These pre-flight checks need a fresh quote; when the service has none, the trade server performs
them instead and the error carries its `mt5RetCode`.

The symbol's rules are checked too: `tradeMode` (`-4011` disabled, `-4013` long only, `-4014` short
only, `-4015` close only), `orderModes` (`-4016` for a `type` — or an `sl` / `tp` — the symbol does
not allow) and `expirationModes` (`-4012`). An unknown `symbol` is `-1121`.

A retry with a `newClientOrderId` this key already used skips all of this and returns the stored
outcome — see [Idempotency](/trade.md#idempotency).

## Response Example

**Response — `ACK` (default)**

```json
{
  "login": 100123,
  "clientOrderId": "bot-001",
  "symbol": "XAUUSD",
  "side": "BUY",
  "type": "MARKET",
  "volume": "0.10",
  "status": "ACCEPTED",
  "transactTime": 1789012345690
}
```

**Response — `RESULT`, market order filled**

```json
{
  "login": 100123,
  "clientOrderId": "bot-001",
  "symbol": "XAUUSD",
  "side": "BUY",
  "type": "MARKET",
  "volume": "0.10",
  "status": "FILLED",
  "orderId": 44412345,
  "dealId": 55512345,
  "positionId": 44412345,
  "price": "2331.42",
  "executedVolume": "0.10",
  "sl": "2320.00",
  "tp": "2350.00",
  "mt5RetCode": 10009,
  "transactTime": 1789012345812
}
```

**Response — pending order placed** (`RESULT`)

```json
{
  "login": 100123,
  "clientOrderId": "bot-002",
  "symbol": "XAUUSD",
  "side": "BUY",
  "type": "BUY_LIMIT",
  "volume": "0.10",
  "status": "NEW",
  "orderId": 44412350,
  "price": "2325.00",
  "timeInForce": "GTC",
  "mt5RetCode": 10008,
  "transactTime": 1789012345812
}
```

**Response — rejected** (HTTP `400`)

```json
{
  "code": -2018,
  "msg": "Insufficient margin on the trading account.",
  "mt5RetCode": 10019,
  "status": "REJECTED",
  "clientOrderId": "bot-003",
  "login": 100123
}
```

When the order was recorded and then rejected, the error body carries `status`, `clientOrderId` and
`login` in addition to the standard envelope, so the rejection can be correlated without a second
lookup. A request refused **before** it was recorded — a validation error such as `-1102`, `-4007` or
`-2022` — returns the plain `{"code","msg"}` envelope.

Fields whose value is unknown or does not apply are **omitted**, not sent as `null`: an `ACK`
response carries no `orderId`, `dealId`, `positionId`, `price` or `executedVolume`, and `sl`, `tp`
and `expiration` are absent when the order has none.

**Response fields**

| Field | Type | Description |
| - | - | - |
| `login` | LONG | |
| `clientOrderId` | STRING | Yours if you sent one, otherwise generated. |
| `symbol` | STRING | |
| `side` | ENUM | `BUY` / `SELL`. Derived from `type` for pending orders. |
| `type` | ENUM | As sent. |
| `volume` | DECIMAL | Requested volume, lots. |
| `status` | ENUM | See [Status values](/trade.md#status-values). |
| `orderId` | LONG | MT5 order ticket. Absent until the server assigns one. |
| `dealId` | LONG | MT5 deal ticket. Market fills only. |
| `positionId` | LONG | MT5 position ticket. Market fills only. Under hedging it is typically equal to `orderId` for a newly opened position, but **do not rely on that** — use the value returned. |
| `price` | DECIMAL | Fill price for a market order; order price for a pending order. |
| `executedVolume` | DECIMAL | Filled volume, lots. May be less than `volume` on a partial fill. |
| `sl` / `tp` | DECIMAL | As sent. Absent when none was set. |
| `timeInForce` | ENUM | Pending orders only. |
| `expiration` | LONG | Pending orders only, Unix ms. Absent when none was set. |
| `mt5RetCode` | INT | The trade server's raw return code, when it answered. |
| `transactTime` | LONG | When the API produced this response, Unix ms. |
