# Introduction Source: https://docs.pipsocket.com/ Hosted MT5 accounts behind an API. Pipsocket runs your MT5 accounts on its own hosts, each in its own MT5 terminal, and gives you one API for all of them: trade, read positions and history, and get prices and fills as they happen. ## How a call works Every call is for one account: ```text https://api.pipsocket.com/v1/accounts/{account}/... Authorization: Bearer $PIPSOCKET_KEY ``` The API checks your workspace's key, finds the host that runs the account, and hands the call to the account's terminal. Hosts don't accept connections from the internet: each keeps one connection open to Pipsocket, and calls and events travel over it. ## One call, one MT5 request A trade call is exactly one MT5 trade request (`MqlTradeRequest`), sent once: - **Nothing is changed.** No splitting, no retries, no rounding, no picked filling mode. Fields you leave out are MT5's own empty values (0, `""`, `gtc`). - **MT5's answer, as it is.** A fill and a rejection both come back as `200` with MT5's `retcode`. A rejection is not an HTTP error: read the `retcode`. - **5 seconds for the broker.** If the trade server hasn't answered by then, you get `202` with `"state": "pending"`. The request is never sent again; [look it up](/api/look-up-a-request) or watch for it on the [stream](/websocket). - **Safe to retry.** Send an `Idempotency-Key` and a repeat returns the first request instead of trading again. ## What's here - [Quickstart](/quickstart): your first calls, from key to a closed position. - [Authentication](/authentication): your workspace's key, and rolling it. - [Accounts and ids](/accounts): account ids, tickets, request ids, and times. - [API reference](/api/place-an-order): every call, its fields with their MT5 fields, and its answers. - [The WebSocket stream](/websocket): fills, deals, prices and the account as they happen, and calls over the same socket. - [Errors and retcodes](/errors), the [MT5 field map](/mt5-field-map) and [rate limits](/rate-limits). The API reference is generated from the engine's own routes, and the whole API is also an [OpenAPI document](/openapi.json). For tools and LLMs, [`/llms.txt`](/llms.txt) lists every page as Markdown, and [`/llms-full.txt`](/llms-full.txt) is all of them in one file. --- # Quickstart Source: https://docs.pipsocket.com/quickstart From your workspace's key to an order placed and closed. You need an MT5 account connected in the [dashboard](https://app.pipsocket.com) (Accounts, then Connect account). Use a demo account while you try things. ## 1. Get your key Open **API key** in the dashboard and make the workspace's key. It is shown once: copy it and keep it on your server. ```bash export PIPSOCKET_KEY=psk_... ``` The same page lists your accounts' ids. Take the one you'll trade: ```bash export ACCOUNT=acc_01m6tx3k9f2qw8r7bznd5yvh4c ``` ## 2. Read the account ```bash curl https://api.pipsocket.com/v1/accounts/$ACCOUNT \ -H "Authorization: Bearer $PIPSOCKET_KEY" ``` `status` is `connected` once the terminal is logged in to your broker, and `balance`, `equity` and `margin` are from its last report (it reports every second). If `trade_allowed` is `false` (an investor login, for example), MT5 rejects trades. ## 3. Look at the symbol ```bash curl https://api.pipsocket.com/v1/accounts/$ACCOUNT/symbols/EURUSD \ -H "Authorization: Bearer $PIPSOCKET_KEY" ``` Note three things from the answer: - `filling_modes`: the `type_filling` values the symbol allows. There is no default, so you choose one. - `volume_min`, `volume_max` and `volume_step`: MT5 rejects a volume outside them. - `execution`: with `instant` or `request`, send a `price` (and a `deviation`); with `market` or `exchange`, MT5 ignores it. The symbol's name is exactly the broker's: `EURUSD` on one broker can be `EURUSD.r` on another. `GET /symbols` lists them all. ## 4. Place an order Give the order its own `Idempotency-Key`, and keep it until you have the answer: ```bash IDEMPOTENCY_KEY=$(uuidgen) curl -X POST https://api.pipsocket.com/v1/accounts/$ACCOUNT/orders \ -H "Authorization: Bearer $PIPSOCKET_KEY" \ -H "Idempotency-Key: $IDEMPOTENCY_KEY" \ -H "Content-Type: application/json" \ -d '{ "symbol": "EURUSD", "type": "buy", "volume": 0.01, "type_filling": "ioc" }' ``` The answer is the request as recorded for the terminal (`sent`), its `state`, and MT5's answer (`result`): - `200` with `"state": "done"`: MT5 answered (the trade server, or the terminal refusing to send it). `result.retcode` says how: `10009` (`TRADE_RETCODE_DONE`) is a fill; anything else is a rejection or a partial fill, see [retcodes](/errors#mt5-retcodes). - `202` with `"state": "pending"`: no answer within 5 seconds. Don't send it again. Look it up with its id: ```bash curl https://api.pipsocket.com/v1/accounts/$ACCOUNT/requests/req_5f0c2a9e41d7b3a8c6e2f190 \ -H "Authorization: Bearer $PIPSOCKET_KEY" ``` If the call itself failed (a timeout, a dropped connection), run the same `curl` again with the **same** `$IDEMPOTENCY_KEY`: if the first one was recorded you get it back, and nothing is sent twice. Make a new key only for a new order. ## 5. Close the position List the open positions and take the position's `ticket`: ```bash curl https://api.pipsocket.com/v1/accounts/$ACCOUNT/positions \ -H "Authorization: Bearer $PIPSOCKET_KEY" ``` Then close all of it (or part, with a smaller `volume`): ```bash IDEMPOTENCY_KEY=$(uuidgen) curl -X POST https://api.pipsocket.com/v1/accounts/$ACCOUNT/positions/881402311/close \ -H "Authorization: Bearer $PIPSOCKET_KEY" \ -H "Idempotency-Key: $IDEMPOTENCY_KEY" \ -H "Content-Type: application/json" \ -d '{ "volume": 0.01, "type_filling": "ioc" }' ``` ## Next - Get fills, deals and prices as they happen on [the WebSocket stream](/websocket). - Every call and field is in the [API reference](/api/place-an-order). - Flatten an account in one call with the [kill switch](/api/kill-switch). --- # Authentication Source: https://docs.pipsocket.com/authentication Your workspace's API key, and rolling it. Every call carries your workspace's key as a bearer token: ```bash curl https://api.pipsocket.com/v1/accounts/acc_01m6tx3k9f2qw8r7bznd5yvh4c \ -H "Authorization: Bearer $PIPSOCKET_KEY" ``` ## One key per workspace - A workspace has one key, and it works for every account in the workspace. An account in another workspace answers `404 no_such_account`, exactly as an account that doesn't exist. - The key is `psk_` and 43 more characters. It is shown once, when it is made: Pipsocket keeps only its hash and its last four characters. - Make it on the dashboard's **API key** page. The workspace's owners and admins can make and roll it; members see its last four characters, who made it and when. - Keep it on your server. The API doesn't answer browsers' cross-origin requests, so a key in a web page wouldn't work anyway. - A new key works within about a minute, as it reaches every Cloudflare location. - The key is checked on every REST call, and on a stream once, when it connects. ## Rolling the key Rolling gives the workspace a new key and retires the current one. On the **API key** page, choose **Roll key** and confirm; the new key is shown once, and the dialog stays open until you tick that you've saved it. The old key stops working for new requests and new streams within about a minute, so put the new key everywhere the old one was used straight away. If Pipsocket can't retire the old key at once, the page says so and keeps trying every minute: until then the old key may still work. A stream checks the key only when it connects. A stream opened with the old key stays open, and its calls still work, until it closes. After rolling a key you suspect someone else has, close your own streams and connect them again with the new key; a stream someone else opened stays open until it closes, so engage the [kill switch](/api/kill-switch) if they could trade, and contact support. ## Refusals | Status | `error` | Meaning | | --- | --- | --- | | 401 | `missing_api_key` | No key: send `Authorization: Bearer `. | | 401 | `invalid_api_key` | Not a workspace's current key (a rolled key stops working within about a minute). | | 404 | `no_such_account` | No such account, or one your workspace doesn't have. | The stream takes the key the same way, on its WebSocket upgrade: see [the WebSocket stream](/websocket). --- # Accounts and ids Source: https://docs.pipsocket.com/accounts Account ids, MT5 tickets, request ids, and the times the API uses. ## Accounts An account is one MT5 login on one broker server, running in its own MT5 terminal on a Pipsocket host. You connect it in the [dashboard](https://app.pipsocket.com) with its login, server and password; from then on the API reaches it by its id. An account's id is `acc_` and 26 characters, such as `acc_01m6tx3k9f2qw8r7bznd5yvh4c`. The dashboard's **API key** page lists your accounts' ids, each with a copy button. [`GET /v1/accounts/{account}`](/api/account) tells you how its terminal is doing (`status`): | `status` | Meaning | | --- | --- | | `starting` | The terminal is starting, or logging in. | | `connected` | Logged in to the broker: ready to trade. | | `disconnected` | The terminal has lost the broker's trade server; it reconnects by itself. | | `unreachable` | The broker's server can't be reached; the terminal keeps trying. | | `stopped` | Stopped from the dashboard. | | `auth_failed` | The broker refused the login. Fix the password in the dashboard. | | `server_not_found` | The broker's server name wasn't found. | | `login_unknown` | The terminal went away while trying a password the broker hadn't confirmed yet; give the login again. | | `refused` | Pipsocket stopped the terminal as it can't be right (for example, it logged in to another account). | The last four need someone to act in the dashboard. While the terminal isn't running (stopped, starting, or being replaced), calls that need it answer `503 account_not_connected`; [`GET /v1/accounts/{account}`](/api/account) still answers, and the [kill switch](/api/kill-switch) still engages. A terminal that has lost the broker still answers, and MT5 rejects trades with its own retcode. ## MT5's tickets Orders, deals and positions keep MT5's own numbers: - **`ticket`** of a position or a pending order: what you pass to [close](/api/close-a-position), [modify](/api/modify-an-order) or [cancel](/api/cancel-an-order) it. - A position's **`identifier`** stays the same for its whole life, even if the broker changes its ticket. Deals name their position by it (`position`). - A trade answer's `result` has the `order` and `deal` MT5 made. ## Request ids Each trade call is recorded as a request, `req_` and 24 characters, returned as `request`. Look it up with [`GET /requests/{request}`](/api/look-up-a-request) for 7 days. Its `state`: | `state` | Meaning | | --- | --- | | `pending` | Sent, with no answer from the trade server yet. It is never sent again. | | `done` | MT5 answered: `result.retcode` says whether it filled, was placed or was rejected. | | `unknown` | No answer within 130 seconds. If the terminal reports the answer later, the request becomes `done`; check positions and history meanwhile. | | `refused` | The terminal didn't send it; `result` says why. | An `Idempotency-Key` header, 1 to 128 characters, makes a trade call safe to repeat: a call with a key the account used in the last 7 days returns that first request, as it stands now, and sends nothing. ## Times - `time_msc`, `time_setup_msc`, `time_done_msc` and `server_time` are the **broker's server time**, as MT5 reports it, not UTC: milliseconds (or seconds, for `server_time`) since 1970 in the broker's time zone. - History ranges (`from`, `to`) and a pending order's `expiration` are broker server time too, in seconds. - The kill switch's `since` is UTC, in seconds. --- # Place an order Source: https://docs.pipsocket.com/api/place-an-order A market or pending order, sent once. All calls: `https://api.pipsocket.com`, with `Authorization: Bearer `. ## Place an order `POST /v1/accounts/{account}/orders` Sends one trade request (MT5's `TRADE_ACTION_DEAL` for `buy` and `sell`, `TRADE_ACTION_PENDING` for the rest) to the account's terminal, with the stop loss and take profit in the same request, and waits up to 5 seconds for the trade server's answer. The request goes as you send it: nothing is split, retried, rounded or adjusted. ### Path - `account` (string, required): The account's id, `acc_` and 26 characters, as the dashboard shows it. ### Headers - `Idempotency-Key` (string, optional): Your own key for this request, 1 to 128 characters. A request with a key the account has used before (in the last 7 days) is not sent: the first request's answer comes back instead, as it stands now. ### Body A market or pending order. Fields left out are sent as MT5's empty values (0, "", `gtc`); there is no other default. Fields not listed here are refused. - `symbol` (string, required, MT5 `symbol`): The symbol exactly as the broker names it, such as `EURUSD`. - `type` (enum, required, MT5 `type`): What to send. `buy` and `sell` fill now; the others wait at `price`. `close_by` is refused here: use Close by. One of: `buy`, `sell`, `buy_limit`, `sell_limit`, `buy_stop`, `sell_stop`, `buy_stop_limit`, `sell_stop_limit`, `close_by`. - `volume` (number, required, MT5 `volume`): Lots. MT5 rejects a volume outside the symbol's minimum, maximum and step. - `type_filling` (enum, required, MT5 `type_filling`): How the order may fill. Required: each symbol allows its own modes (its `filling_modes`). One of: `fok`, `ioc`, `return`, `boc`. - `price` (number, optional, MT5 `price`): Required for pending orders: the price the order waits for. For a market order it is sent as given (0 if left out): brokers with instant or request execution need it, those with market or exchange execution ignore it. - `stoplimit` (number, optional, MT5 `stoplimit`): Required for `buy_stop_limit` and `sell_stop_limit`: the price of the limit order placed once `price` is reached. - `sl` (number, optional, MT5 `sl`): Stop loss price, set in the same request. 0 or left out: none. - `tp` (number, optional, MT5 `tp`): Take profit price, set in the same request. 0 or left out: none. - `deviation` (integer, optional, MT5 `deviation`): The largest difference from `price` MT5 accepts, in points, for instant or request execution. - `type_time` (enum, optional, MT5 `type_time`): How long a pending order lasts. `gtc` if left out. One of: `gtc`, `day`, `specified`, `specified_day`. - `expiration` (integer, optional, MT5 `expiration`): When a pending order expires: broker server time, seconds since 1970. Required for `type_time` `specified` and `specified_day`. - `magic` (integer, optional, MT5 `magic`): Your own number for the order, kept by MT5 on the order, its deals and its position. - `comment` (string, optional, MT5 `comment`): Up to 31 characters, kept by MT5 on the order. Brokers may replace it. ### Response - `request` (string): The request's id (`req_...`): look it up with `GET /requests/{request}`. - `state` (enum): A trade request's state: `pending` (sent, no answer yet: never sent again), `done` (MT5 answered: filled, placed or rejected, as `result.retcode` says), `unknown` (no answer within 130 seconds; it becomes `done` if the terminal reports the answer later) or `refused` (the terminal did not send it). One of: `pending`, `done`, `unknown`, `refused`. - `sent` (object): MT5's `MqlTradeRequest`, field for field, exactly as recorded to send to the terminal: the request's `state` and `result` say whether it reached MT5. Fields the call does not use carry MT5's empty values (0, "", `fok`, `gtc`). - `action` (enum, MT5 `action`): What the request does. One of: `deal`, `pending`, `sltp`, `modify`, `remove`, `close_by`. - `symbol` (string, MT5 `symbol`): The symbol, exactly as the broker names it. - `type` (enum, MT5 `type`): The order type. One of: `buy`, `sell`, `buy_limit`, `sell_limit`, `buy_stop`, `sell_stop`, `buy_stop_limit`, `sell_stop_limit`, `close_by`. - `volume` (number, MT5 `volume`): Lots. - `price` (number, MT5 `price`): The price: a pending order's, or the one instant and request execution trade at. - `stoplimit` (number, MT5 `stoplimit`): A stop-limit order's limit price, placed once `price` is reached. - `sl` (number, MT5 `sl`): Stop loss price; 0 for none. - `tp` (number, MT5 `tp`): Take profit price; 0 for none. - `deviation` (integer, MT5 `deviation`): The largest difference from `price` MT5 accepts, in points. - `type_filling` (enum, MT5 `type_filling`): How the order may fill. One of: `fok`, `ioc`, `return`, `boc`. - `type_time` (enum, MT5 `type_time`): How long a pending order lasts. One of: `gtc`, `day`, `specified`, `specified_day`. - `expiration` (integer, MT5 `expiration`): Broker server time, seconds since 1970, as MT5 takes it. - `order` (integer, MT5 `order`): The pending order the request is about (modify, remove). - `position` (integer, MT5 `position`): The position the request is about (close, stops, close by). - `position_by` (integer, MT5 `position_by`): The opposite position, for close by. - `magic` (integer, MT5 `magic`): Your own number, kept by MT5 on the order, its deals and its position. - `comment` (string, MT5 `comment`): Up to 31 characters, kept by MT5 on the order. - `result` (object, or null): MT5's `MqlTradeResult` once `done`; why it was not sent once `refused`; otherwise null. - `message` (string): What the answer means, in a sentence. ### Answers - 200: MT5's answer: the request is `done` (filled, placed or rejected, as the retcode says), or `unknown` for a repeated key whose first request never got an answer. - 202: No answer from the trade server within 5 seconds: the request is `pending` and is never sent again. Look it up to see how it ended. - 401: - `missing_api_key`: No API key: send it as `Authorization: Bearer `.; `invalid_api_key`: The key is not a workspace's current key (a rolled key stops working within about a minute). - 404: - `no_such_account`: No such account, or one the key's workspace doesn't have: the two look the same. - 422: - `invalid_request`: A field, query parameter or header is missing, malformed or not allowed, or the body is not JSON. Nothing was sent. - 423: - `kill_switch_engaged`: The account's kill switch is engaged: new orders and changes to pending orders are refused until it is lifted. Nothing was sent. - 503: - `account_not_connected`: The account's terminal is not connected to the engine (stopped, starting, or restarting). Nothing was sent, except by the kill switch: engaging it still engages it, and may already have deleted pending orders.; `bridge_outdated`: The account's terminal runs an older bridge that can't trade: restart the account to update it. Nothing was sent.; `account_restarting`: The account's terminal is being replaced. Nothing was sent; try again in a minute.; `engine_busy`: The account's engine host has too many calls in flight (256). Nothing was done; try again.; `engine_unavailable`: The account's engine host is not connected to Pipsocket, or disconnected while the call waited. A trade it already had is still settled: look it up.; a stored request whose state is `refused`: the terminal did not send it (for example `busy`, with 1,000 trades already waiting for the trade server). `result` says why. - 504: - `engine_timeout`: The account's engine did not answer within 30 seconds. ### Example ```bash # A new key for each new trade; send the same one to retry it. IDEMPOTENCY_KEY=$(uuidgen) curl -X POST "https://api.pipsocket.com/v1/accounts/acc_01m6tx3k9f2qw8r7bznd5yvh4c/orders" \ -H "Authorization: Bearer $PIPSOCKET_KEY" \ -H "Idempotency-Key: $IDEMPOTENCY_KEY" \ -H "Content-Type: application/json" \ -d '{ "sl": 1.079, "symbol": "EURUSD", "type": "buy", "type_filling": "ioc", "volume": 0.1 }' ``` 200 done: ```json { "message": "The request was completed.", "request": "req_5f0c2a9e41d7b3a8c6e2f190", "result": { "ask": 1.08412, "bid": 1.0841, "comment": "Request executed", "deal": 771203455, "order": 881402311, "position": 0, "price": 1.08412, "retcode": 10009, "retcode_external": 0, "retcode_name": "TRADE_RETCODE_DONE", "volume": 0.1 }, "sent": { "action": "deal", "comment": "", "deviation": 0, "expiration": 0, "magic": 0, "order": 0, "position": 0, "position_by": 0, "price": 0, "sl": 1.079, "stoplimit": 0, "symbol": "EURUSD", "tp": 0, "type": "buy", "type_filling": "ioc", "type_time": "gtc", "volume": 0.1 }, "state": "done" } ``` 200 rejected: ```json { "message": "The stop loss or take profit is invalid for this symbol or too close to the price.", "request": "req_5f0c2a9e41d7b3a8c6e2f190", "result": { "ask": 1.08412, "bid": 1.0841, "comment": "Invalid stops", "deal": 0, "order": 0, "position": 0, "price": 0, "retcode": 10016, "retcode_external": 0, "retcode_name": "TRADE_RETCODE_INVALID_STOPS", "volume": 0 }, "sent": { "action": "deal", "comment": "", "deviation": 0, "expiration": 0, "magic": 0, "order": 0, "position": 0, "position_by": 0, "price": 0, "sl": 1.079, "stoplimit": 0, "symbol": "EURUSD", "tp": 0, "type": "buy", "type_filling": "ioc", "type_time": "gtc", "volume": 0.1 }, "state": "done" } ``` 202 pending: ```json { "message": "No answer from the trade server yet. The order may still execute; it is not sent again.", "request": "req_5f0c2a9e41d7b3a8c6e2f190", "result": null, "sent": { "action": "deal", "comment": "", "deviation": 0, "expiration": 0, "magic": 0, "order": 0, "position": 0, "position_by": 0, "price": 0, "sl": 1.079, "stoplimit": 0, "symbol": "EURUSD", "tp": 0, "type": "buy", "type_filling": "ioc", "type_time": "gtc", "volume": 0.1 }, "state": "pending" } ``` --- # Check an order Source: https://docs.pipsocket.com/api/check-an-order MT5's dry run: whether it would pass, and its margin. All calls: `https://api.pipsocket.com`, with `Authorization: Bearer `. ## Check an order `POST /v1/accounts/{account}/orders/check` MT5's `OrderCheck`: whether the order would pass, and the margin it would take. Nothing is sent to the trade server. Takes the same body as Place an order. ### Path - `account` (string, required): The account's id, `acc_` and 26 characters, as the dashboard shows it. ### Body A market or pending order. Fields left out are sent as MT5's empty values (0, "", `gtc`); there is no other default. Fields not listed here are refused. - `symbol` (string, required, MT5 `symbol`): The symbol exactly as the broker names it, such as `EURUSD`. - `type` (enum, required, MT5 `type`): What to send. `buy` and `sell` fill now; the others wait at `price`. `close_by` is refused here: use Close by. One of: `buy`, `sell`, `buy_limit`, `sell_limit`, `buy_stop`, `sell_stop`, `buy_stop_limit`, `sell_stop_limit`, `close_by`. - `volume` (number, required, MT5 `volume`): Lots. MT5 rejects a volume outside the symbol's minimum, maximum and step. - `type_filling` (enum, required, MT5 `type_filling`): How the order may fill. Required: each symbol allows its own modes (its `filling_modes`). One of: `fok`, `ioc`, `return`, `boc`. - `price` (number, optional, MT5 `price`): Required for pending orders: the price the order waits for. For a market order it is sent as given (0 if left out): brokers with instant or request execution need it, those with market or exchange execution ignore it. - `stoplimit` (number, optional, MT5 `stoplimit`): Required for `buy_stop_limit` and `sell_stop_limit`: the price of the limit order placed once `price` is reached. - `sl` (number, optional, MT5 `sl`): Stop loss price, set in the same request. 0 or left out: none. - `tp` (number, optional, MT5 `tp`): Take profit price, set in the same request. 0 or left out: none. - `deviation` (integer, optional, MT5 `deviation`): The largest difference from `price` MT5 accepts, in points, for instant or request execution. - `type_time` (enum, optional, MT5 `type_time`): How long a pending order lasts. `gtc` if left out. One of: `gtc`, `day`, `specified`, `specified_day`. - `expiration` (integer, optional, MT5 `expiration`): When a pending order expires: broker server time, seconds since 1970. Required for `type_time` `specified` and `specified_day`. - `magic` (integer, optional, MT5 `magic`): Your own number for the order, kept by MT5 on the order, its deals and its position. - `comment` (string, optional, MT5 `comment`): Up to 31 characters, kept by MT5 on the order. Brokers may replace it. ### Response - `sent` (object): MT5's `MqlTradeRequest`, field for field, exactly as recorded to send to the terminal: the request's `state` and `result` say whether it reached MT5. Fields the call does not use carry MT5's empty values (0, "", `fok`, `gtc`). - `action` (enum, MT5 `action`): What the request does. One of: `deal`, `pending`, `sltp`, `modify`, `remove`, `close_by`. - `symbol` (string, MT5 `symbol`): The symbol, exactly as the broker names it. - `type` (enum, MT5 `type`): The order type. One of: `buy`, `sell`, `buy_limit`, `sell_limit`, `buy_stop`, `sell_stop`, `buy_stop_limit`, `sell_stop_limit`, `close_by`. - `volume` (number, MT5 `volume`): Lots. - `price` (number, MT5 `price`): The price: a pending order's, or the one instant and request execution trade at. - `stoplimit` (number, MT5 `stoplimit`): A stop-limit order's limit price, placed once `price` is reached. - `sl` (number, MT5 `sl`): Stop loss price; 0 for none. - `tp` (number, MT5 `tp`): Take profit price; 0 for none. - `deviation` (integer, MT5 `deviation`): The largest difference from `price` MT5 accepts, in points. - `type_filling` (enum, MT5 `type_filling`): How the order may fill. One of: `fok`, `ioc`, `return`, `boc`. - `type_time` (enum, MT5 `type_time`): How long a pending order lasts. One of: `gtc`, `day`, `specified`, `specified_day`. - `expiration` (integer, MT5 `expiration`): Broker server time, seconds since 1970, as MT5 takes it. - `order` (integer, MT5 `order`): The pending order the request is about (modify, remove). - `position` (integer, MT5 `position`): The position the request is about (close, stops, close by). - `position_by` (integer, MT5 `position_by`): The opposite position, for close by. - `magic` (integer, MT5 `magic`): Your own number, kept by MT5 on the order, its deals and its position. - `comment` (string, MT5 `comment`): Up to 31 characters, kept by MT5 on the order. - `result` (object): MT5's `MqlTradeCheckResult`. - `passed` (boolean): Whether `OrderCheck` passed the request. - `retcode` (integer, MT5 `retcode`): MT5's return code: 0 when the check passed. - `retcode_name` (enum): The return code's name; `UNKNOWN` for a code MT5 doesn't document. One of: `OK`, `TRADE_RETCODE_REQUOTE`, `TRADE_RETCODE_REJECT`, `TRADE_RETCODE_CANCEL`, `TRADE_RETCODE_PLACED`, `TRADE_RETCODE_DONE`, `TRADE_RETCODE_DONE_PARTIAL`, `TRADE_RETCODE_ERROR`, `TRADE_RETCODE_TIMEOUT`, `TRADE_RETCODE_INVALID`, `TRADE_RETCODE_INVALID_VOLUME`, `TRADE_RETCODE_INVALID_PRICE`, `TRADE_RETCODE_INVALID_STOPS`, `TRADE_RETCODE_TRADE_DISABLED`, `TRADE_RETCODE_MARKET_CLOSED`, `TRADE_RETCODE_NO_MONEY`, `TRADE_RETCODE_PRICE_CHANGED`, `TRADE_RETCODE_PRICE_OFF`, `TRADE_RETCODE_INVALID_EXPIRATION`, `TRADE_RETCODE_ORDER_CHANGED`, `TRADE_RETCODE_TOO_MANY_REQUESTS`, `TRADE_RETCODE_NO_CHANGES`, `TRADE_RETCODE_SERVER_DISABLES_AT`, `TRADE_RETCODE_CLIENT_DISABLES_AT`, `TRADE_RETCODE_LOCKED`, `TRADE_RETCODE_FROZEN`, `TRADE_RETCODE_INVALID_FILL`, `TRADE_RETCODE_CONNECTION`, `TRADE_RETCODE_ONLY_REAL`, `TRADE_RETCODE_LIMIT_ORDERS`, `TRADE_RETCODE_LIMIT_VOLUME`, `TRADE_RETCODE_INVALID_ORDER`, `TRADE_RETCODE_POSITION_CLOSED`, `TRADE_RETCODE_INVALID_CLOSE_VOLUME`, `TRADE_RETCODE_CLOSE_ORDER_EXIST`, `TRADE_RETCODE_LIMIT_POSITIONS`, `TRADE_RETCODE_REJECT_CANCEL`, `TRADE_RETCODE_LONG_ONLY`, `TRADE_RETCODE_SHORT_ONLY`, `TRADE_RETCODE_CLOSE_ONLY`, `TRADE_RETCODE_FIFO_CLOSE`, `TRADE_RETCODE_HEDGE_PROHIBITED`, `UNKNOWN`. - `comment` (string, MT5 `comment`): - `balance` (number, MT5 `balance`): The balance after the trade. - `equity` (number, MT5 `equity`): The equity after the trade. - `profit` (number, MT5 `profit`): The floating profit after the trade. - `margin` (number, MT5 `margin`): The margin the trade takes. - `margin_free` (number, MT5 `margin_free`): The free margin after the trade. - `margin_level` (number, MT5 `margin_level`): The margin level after the trade, in percent. - `message` (string): The return code's meaning, in a sentence. ### Answers - 200: MT5's check result. - 401: - `missing_api_key`: No API key: send it as `Authorization: Bearer `.; `invalid_api_key`: The key is not a workspace's current key (a rolled key stops working within about a minute). - 404: - `no_such_account`: No such account, or one the key's workspace doesn't have: the two look the same. - 422: - `invalid_request`: A field, query parameter or header is missing, malformed or not allowed, or the body is not JSON. Nothing was sent. - 503: - `account_not_connected`: The account's terminal is not connected to the engine (stopped, starting, or restarting). Nothing was sent, except by the kill switch: engaging it still engages it, and may already have deleted pending orders.; `bridge_outdated`: The account's terminal runs an older bridge that can't trade: restart the account to update it. Nothing was sent.; `bad_command`: The terminal refused the command, for example a negative `expiration`, or a history range MT5 can't select.; `engine_busy`: The account's engine host has too many calls in flight (256). Nothing was done; try again.; `engine_unavailable`: The account's engine host is not connected to Pipsocket, or disconnected while the call waited. A trade it already had is still settled: look it up. - 504: - `terminal_timeout`: The account's terminal did not answer within 5 seconds.; `engine_timeout`: The account's engine did not answer within 30 seconds. ### Example ```bash curl -X POST "https://api.pipsocket.com/v1/accounts/acc_01m6tx3k9f2qw8r7bznd5yvh4c/orders/check" \ -H "Authorization: Bearer $PIPSOCKET_KEY" \ -H "Content-Type: application/json" \ -d '{ "sl": 1.079, "symbol": "EURUSD", "type": "buy", "type_filling": "ioc", "volume": 0.1 }' ``` 200 passed: ```json { "message": "The request passed the check.", "result": { "balance": 10000, "comment": "Done", "equity": 10000, "margin": 108.41, "margin_free": 9891.59, "margin_level": 9224.24, "passed": true, "profit": 0, "retcode": 0, "retcode_name": "OK" }, "sent": { "action": "deal", "comment": "", "deviation": 0, "expiration": 0, "magic": 0, "order": 0, "position": 0, "position_by": 0, "price": 0, "sl": 1.079, "stoplimit": 0, "symbol": "EURUSD", "tp": 0, "type": "buy", "type_filling": "ioc", "type_time": "gtc", "volume": 0.1 } } ``` --- # Look up a request Source: https://docs.pipsocket.com/api/look-up-a-request A trade request and MT5's answer. All calls: `https://api.pipsocket.com`, with `Authorization: Bearer `. ## Look up a request `GET /v1/accounts/{account}/requests/{request}` A trade request as it stands now: the request as recorded for the terminal, its state, and MT5's answer. Requests are kept for 7 days. ### Path - `account` (string, required): The account's id, `acc_` and 26 characters, as the dashboard shows it. - `request` (string, required): The request's id (`req_...`), from the trade call's answer. ### Response - `request` (string): The request's id (`req_...`): look it up with `GET /requests/{request}`. - `state` (enum): A trade request's state: `pending` (sent, no answer yet: never sent again), `done` (MT5 answered: filled, placed or rejected, as `result.retcode` says), `unknown` (no answer within 130 seconds; it becomes `done` if the terminal reports the answer later) or `refused` (the terminal did not send it). One of: `pending`, `done`, `unknown`, `refused`. - `sent` (object): MT5's `MqlTradeRequest`, field for field, exactly as recorded to send to the terminal: the request's `state` and `result` say whether it reached MT5. Fields the call does not use carry MT5's empty values (0, "", `fok`, `gtc`). - `action` (enum, MT5 `action`): What the request does. One of: `deal`, `pending`, `sltp`, `modify`, `remove`, `close_by`. - `symbol` (string, MT5 `symbol`): The symbol, exactly as the broker names it. - `type` (enum, MT5 `type`): The order type. One of: `buy`, `sell`, `buy_limit`, `sell_limit`, `buy_stop`, `sell_stop`, `buy_stop_limit`, `sell_stop_limit`, `close_by`. - `volume` (number, MT5 `volume`): Lots. - `price` (number, MT5 `price`): The price: a pending order's, or the one instant and request execution trade at. - `stoplimit` (number, MT5 `stoplimit`): A stop-limit order's limit price, placed once `price` is reached. - `sl` (number, MT5 `sl`): Stop loss price; 0 for none. - `tp` (number, MT5 `tp`): Take profit price; 0 for none. - `deviation` (integer, MT5 `deviation`): The largest difference from `price` MT5 accepts, in points. - `type_filling` (enum, MT5 `type_filling`): How the order may fill. One of: `fok`, `ioc`, `return`, `boc`. - `type_time` (enum, MT5 `type_time`): How long a pending order lasts. One of: `gtc`, `day`, `specified`, `specified_day`. - `expiration` (integer, MT5 `expiration`): Broker server time, seconds since 1970, as MT5 takes it. - `order` (integer, MT5 `order`): The pending order the request is about (modify, remove). - `position` (integer, MT5 `position`): The position the request is about (close, stops, close by). - `position_by` (integer, MT5 `position_by`): The opposite position, for close by. - `magic` (integer, MT5 `magic`): Your own number, kept by MT5 on the order, its deals and its position. - `comment` (string, MT5 `comment`): Up to 31 characters, kept by MT5 on the order. - `result` (object, or null): MT5's `MqlTradeResult` once `done`; why it was not sent once `refused`; otherwise null. - `message` (string): What the answer means, in a sentence. ### Answers - 200: The request is `done`, or `unknown`: the trade server's answer did not arrive in time. - 202: The request is still `pending`. - 401: - `missing_api_key`: No API key: send it as `Authorization: Bearer `.; `invalid_api_key`: The key is not a workspace's current key (a rolled key stops working within about a minute). - 404: - `no_such_account`: No such account, or one the key's workspace doesn't have: the two look the same.; `no_such_request`: The account has no request with that id (requests are kept 7 days). - 503: - `engine_busy`: The account's engine host has too many calls in flight (256). Nothing was done; try again.; `engine_unavailable`: The account's engine host is not connected to Pipsocket, or disconnected while the call waited. A trade it already had is still settled: look it up.; the request's state is `refused`: the terminal did not send it. `result` says why. - 504: - `engine_timeout`: The account's engine did not answer within 30 seconds. ### Example ```bash curl "https://api.pipsocket.com/v1/accounts/acc_01m6tx3k9f2qw8r7bznd5yvh4c/requests/req_5f0c2a9e41d7b3a8c6e2f190" \ -H "Authorization: Bearer $PIPSOCKET_KEY" ``` 200 done: ```json { "message": "The request was completed.", "request": "req_5f0c2a9e41d7b3a8c6e2f190", "result": { "ask": 1.08412, "bid": 1.0841, "comment": "Request executed", "deal": 771203455, "order": 881402311, "position": 0, "price": 1.08412, "retcode": 10009, "retcode_external": 0, "retcode_name": "TRADE_RETCODE_DONE", "volume": 0.1 }, "sent": { "action": "deal", "comment": "", "deviation": 0, "expiration": 0, "magic": 0, "order": 0, "position": 0, "position_by": 0, "price": 0, "sl": 1.079, "stoplimit": 0, "symbol": "EURUSD", "tp": 0, "type": "buy", "type_filling": "ioc", "type_time": "gtc", "volume": 0.1 }, "state": "done" } ``` 200 unknown: ```json { "message": "The trade server's answer has not arrived in time. Check positions and history; if the terminal reports it later, this request shows it.", "request": "req_5f0c2a9e41d7b3a8c6e2f190", "result": null, "sent": { "action": "deal", "comment": "", "deviation": 0, "expiration": 0, "magic": 0, "order": 0, "position": 0, "position_by": 0, "price": 0, "sl": 1.079, "stoplimit": 0, "symbol": "EURUSD", "tp": 0, "type": "buy", "type_filling": "ioc", "type_time": "gtc", "volume": 0.1 }, "state": "unknown" } ``` 202 pending: ```json { "message": "No answer from the trade server yet. The order may still execute; it is not sent again.", "request": "req_5f0c2a9e41d7b3a8c6e2f190", "result": null, "sent": { "action": "deal", "comment": "", "deviation": 0, "expiration": 0, "magic": 0, "order": 0, "position": 0, "position_by": 0, "price": 0, "sl": 1.079, "stoplimit": 0, "symbol": "EURUSD", "tp": 0, "type": "buy", "type_filling": "ioc", "type_time": "gtc", "volume": 0.1 }, "state": "pending" } ``` --- # Modify an order Source: https://docs.pipsocket.com/api/modify-an-order A pending order's price, stops and expiry. All calls: `https://api.pipsocket.com`, with `Authorization: Bearer `. ## Modify a pending order `PATCH /v1/accounts/{account}/orders/{order}` Changes a pending order's price, stops and expiry (`TRADE_ACTION_MODIFY`). Every level is given: MT5 replaces them all. ### Path - `account` (string, required): The account's id, `acc_` and 26 characters, as the dashboard shows it. - `order` (integer, required): The pending order's ticket. ### Headers - `Idempotency-Key` (string, optional): Your own key for this request, 1 to 128 characters. A request with a key the account has used before (in the last 7 days) is not sent: the first request's answer comes back instead, as it stands now. ### Body A pending order's new levels. `price`, `sl`, `tp` and `type_time` are all required, as MT5 replaces every level: give the ones you keep as they are. - `price` (number, required, MT5 `price`): The price the order waits for. - `sl` (number, required, MT5 `sl`): Stop loss price; 0 removes it. - `tp` (number, required, MT5 `tp`): Take profit price; 0 removes it. - `type_time` (enum, required, MT5 `type_time`): How long the order lasts. One of: `gtc`, `day`, `specified`, `specified_day`. - `stoplimit` (number, optional, MT5 `stoplimit`): Required when the order is a stop-limit order: the price of the limit order placed once `price` is reached. - `expiration` (integer, optional, MT5 `expiration`): When the order expires: broker server time, seconds since 1970. Required for `type_time` `specified` and `specified_day`. ### Response - `request` (string): The request's id (`req_...`): look it up with `GET /requests/{request}`. - `state` (enum): A trade request's state: `pending` (sent, no answer yet: never sent again), `done` (MT5 answered: filled, placed or rejected, as `result.retcode` says), `unknown` (no answer within 130 seconds; it becomes `done` if the terminal reports the answer later) or `refused` (the terminal did not send it). One of: `pending`, `done`, `unknown`, `refused`. - `sent` (object): MT5's `MqlTradeRequest`, field for field, exactly as recorded to send to the terminal: the request's `state` and `result` say whether it reached MT5. Fields the call does not use carry MT5's empty values (0, "", `fok`, `gtc`). - `action` (enum, MT5 `action`): What the request does. One of: `deal`, `pending`, `sltp`, `modify`, `remove`, `close_by`. - `symbol` (string, MT5 `symbol`): The symbol, exactly as the broker names it. - `type` (enum, MT5 `type`): The order type. One of: `buy`, `sell`, `buy_limit`, `sell_limit`, `buy_stop`, `sell_stop`, `buy_stop_limit`, `sell_stop_limit`, `close_by`. - `volume` (number, MT5 `volume`): Lots. - `price` (number, MT5 `price`): The price: a pending order's, or the one instant and request execution trade at. - `stoplimit` (number, MT5 `stoplimit`): A stop-limit order's limit price, placed once `price` is reached. - `sl` (number, MT5 `sl`): Stop loss price; 0 for none. - `tp` (number, MT5 `tp`): Take profit price; 0 for none. - `deviation` (integer, MT5 `deviation`): The largest difference from `price` MT5 accepts, in points. - `type_filling` (enum, MT5 `type_filling`): How the order may fill. One of: `fok`, `ioc`, `return`, `boc`. - `type_time` (enum, MT5 `type_time`): How long a pending order lasts. One of: `gtc`, `day`, `specified`, `specified_day`. - `expiration` (integer, MT5 `expiration`): Broker server time, seconds since 1970, as MT5 takes it. - `order` (integer, MT5 `order`): The pending order the request is about (modify, remove). - `position` (integer, MT5 `position`): The position the request is about (close, stops, close by). - `position_by` (integer, MT5 `position_by`): The opposite position, for close by. - `magic` (integer, MT5 `magic`): Your own number, kept by MT5 on the order, its deals and its position. - `comment` (string, MT5 `comment`): Up to 31 characters, kept by MT5 on the order. - `result` (object, or null): MT5's `MqlTradeResult` once `done`; why it was not sent once `refused`; otherwise null. - `message` (string): What the answer means, in a sentence. ### Answers - 200: MT5's answer: the request is `done` (filled, placed or rejected, as the retcode says), or `unknown` for a repeated key whose first request never got an answer. - 202: No answer from the trade server within 5 seconds: the request is `pending` and is never sent again. Look it up to see how it ended. - 400: The ticket in the path is not a whole number. No body. - 401: - `missing_api_key`: No API key: send it as `Authorization: Bearer `.; `invalid_api_key`: The key is not a workspace's current key (a rolled key stops working within about a minute). - 404: - `no_such_account`: No such account, or one the key's workspace doesn't have: the two look the same.; `no_such_order`: The account has no pending order with that ticket (read fresh from the terminal). - 422: - `invalid_request`: A field, query parameter or header is missing, malformed or not allowed, or the body is not JSON. Nothing was sent. - 423: - `kill_switch_engaged`: The account's kill switch is engaged: new orders and changes to pending orders are refused until it is lifted. Nothing was sent. - 503: - `account_not_connected`: The account's terminal is not connected to the engine (stopped, starting, or restarting). Nothing was sent, except by the kill switch: engaging it still engages it, and may already have deleted pending orders.; `bridge_outdated`: The account's terminal runs an older bridge that can't trade: restart the account to update it. Nothing was sent.; `account_restarting`: The account's terminal is being replaced. Nothing was sent; try again in a minute.; `engine_busy`: The account's engine host has too many calls in flight (256). Nothing was done; try again.; `engine_unavailable`: The account's engine host is not connected to Pipsocket, or disconnected while the call waited. A trade it already had is still settled: look it up.; a stored request whose state is `refused`: the terminal did not send it (for example `busy`, with 1,000 trades already waiting for the trade server). `result` says why. - 504: - `terminal_timeout`: The account's terminal did not answer within 5 seconds.; `engine_timeout`: The account's engine did not answer within 30 seconds. ### Example ```bash # A new key for each new trade; send the same one to retry it. IDEMPOTENCY_KEY=$(uuidgen) curl -X PATCH "https://api.pipsocket.com/v1/accounts/acc_01m6tx3k9f2qw8r7bznd5yvh4c/orders/881402377" \ -H "Authorization: Bearer $PIPSOCKET_KEY" \ -H "Idempotency-Key: $IDEMPOTENCY_KEY" \ -H "Content-Type: application/json" \ -d '{ "price": 1.074, "sl": 1.069, "tp": 1.09, "type_time": "gtc" }' ``` 200 done: ```json { "message": "The request was completed.", "request": "req_5f0c2a9e41d7b3a8c6e2f190", "result": { "ask": 1.08412, "bid": 1.0841, "comment": "Request executed", "deal": 0, "order": 881402377, "position": 0, "price": 0, "retcode": 10009, "retcode_external": 0, "retcode_name": "TRADE_RETCODE_DONE", "volume": 0 }, "sent": { "action": "modify", "comment": "", "deviation": 0, "expiration": 0, "magic": 0, "order": 881402377, "position": 0, "position_by": 0, "price": 1.074, "sl": 1.069, "stoplimit": 0, "symbol": "EURUSD", "tp": 1.09, "type": "buy", "type_filling": "fok", "type_time": "gtc", "volume": 0 }, "state": "done" } ``` 200 rejected: ```json { "message": "The price is invalid.", "request": "req_5f0c2a9e41d7b3a8c6e2f190", "result": { "ask": 1.08412, "bid": 1.0841, "comment": "Invalid price", "deal": 0, "order": 0, "position": 0, "price": 0, "retcode": 10015, "retcode_external": 0, "retcode_name": "TRADE_RETCODE_INVALID_PRICE", "volume": 0 }, "sent": { "action": "modify", "comment": "", "deviation": 0, "expiration": 0, "magic": 0, "order": 881402377, "position": 0, "position_by": 0, "price": 1.074, "sl": 1.069, "stoplimit": 0, "symbol": "EURUSD", "tp": 1.09, "type": "buy", "type_filling": "fok", "type_time": "gtc", "volume": 0 }, "state": "done" } ``` 202 pending: ```json { "message": "No answer from the trade server yet. The order may still execute; it is not sent again.", "request": "req_5f0c2a9e41d7b3a8c6e2f190", "result": null, "sent": { "action": "modify", "comment": "", "deviation": 0, "expiration": 0, "magic": 0, "order": 881402377, "position": 0, "position_by": 0, "price": 1.074, "sl": 1.069, "stoplimit": 0, "symbol": "EURUSD", "tp": 1.09, "type": "buy", "type_filling": "fok", "type_time": "gtc", "volume": 0 }, "state": "pending" } ``` --- # Cancel an order Source: https://docs.pipsocket.com/api/cancel-an-order Delete a pending order. All calls: `https://api.pipsocket.com`, with `Authorization: Bearer `. ## Cancel a pending order `DELETE /v1/accounts/{account}/orders/{order}` Deletes a pending order (`TRADE_ACTION_REMOVE`). ### Path - `account` (string, required): The account's id, `acc_` and 26 characters, as the dashboard shows it. - `order` (integer, required): The pending order's ticket. ### Headers - `Idempotency-Key` (string, optional): Your own key for this request, 1 to 128 characters. A request with a key the account has used before (in the last 7 days) is not sent: the first request's answer comes back instead, as it stands now. ### Response - `request` (string): The request's id (`req_...`): look it up with `GET /requests/{request}`. - `state` (enum): A trade request's state: `pending` (sent, no answer yet: never sent again), `done` (MT5 answered: filled, placed or rejected, as `result.retcode` says), `unknown` (no answer within 130 seconds; it becomes `done` if the terminal reports the answer later) or `refused` (the terminal did not send it). One of: `pending`, `done`, `unknown`, `refused`. - `sent` (object): MT5's `MqlTradeRequest`, field for field, exactly as recorded to send to the terminal: the request's `state` and `result` say whether it reached MT5. Fields the call does not use carry MT5's empty values (0, "", `fok`, `gtc`). - `action` (enum, MT5 `action`): What the request does. One of: `deal`, `pending`, `sltp`, `modify`, `remove`, `close_by`. - `symbol` (string, MT5 `symbol`): The symbol, exactly as the broker names it. - `type` (enum, MT5 `type`): The order type. One of: `buy`, `sell`, `buy_limit`, `sell_limit`, `buy_stop`, `sell_stop`, `buy_stop_limit`, `sell_stop_limit`, `close_by`. - `volume` (number, MT5 `volume`): Lots. - `price` (number, MT5 `price`): The price: a pending order's, or the one instant and request execution trade at. - `stoplimit` (number, MT5 `stoplimit`): A stop-limit order's limit price, placed once `price` is reached. - `sl` (number, MT5 `sl`): Stop loss price; 0 for none. - `tp` (number, MT5 `tp`): Take profit price; 0 for none. - `deviation` (integer, MT5 `deviation`): The largest difference from `price` MT5 accepts, in points. - `type_filling` (enum, MT5 `type_filling`): How the order may fill. One of: `fok`, `ioc`, `return`, `boc`. - `type_time` (enum, MT5 `type_time`): How long a pending order lasts. One of: `gtc`, `day`, `specified`, `specified_day`. - `expiration` (integer, MT5 `expiration`): Broker server time, seconds since 1970, as MT5 takes it. - `order` (integer, MT5 `order`): The pending order the request is about (modify, remove). - `position` (integer, MT5 `position`): The position the request is about (close, stops, close by). - `position_by` (integer, MT5 `position_by`): The opposite position, for close by. - `magic` (integer, MT5 `magic`): Your own number, kept by MT5 on the order, its deals and its position. - `comment` (string, MT5 `comment`): Up to 31 characters, kept by MT5 on the order. - `result` (object, or null): MT5's `MqlTradeResult` once `done`; why it was not sent once `refused`; otherwise null. - `message` (string): What the answer means, in a sentence. ### Answers - 200: MT5's answer: the request is `done` (filled, placed or rejected, as the retcode says), or `unknown` for a repeated key whose first request never got an answer. - 202: No answer from the trade server within 5 seconds: the request is `pending` and is never sent again. Look it up to see how it ended. - 400: The ticket in the path is not a whole number. No body. - 401: - `missing_api_key`: No API key: send it as `Authorization: Bearer `.; `invalid_api_key`: The key is not a workspace's current key (a rolled key stops working within about a minute). - 404: - `no_such_account`: No such account, or one the key's workspace doesn't have: the two look the same. - 422: - `invalid_request`: A field, query parameter or header is missing, malformed or not allowed, or the body is not JSON. Nothing was sent. - 503: - `account_not_connected`: The account's terminal is not connected to the engine (stopped, starting, or restarting). Nothing was sent, except by the kill switch: engaging it still engages it, and may already have deleted pending orders.; `bridge_outdated`: The account's terminal runs an older bridge that can't trade: restart the account to update it. Nothing was sent.; `account_restarting`: The account's terminal is being replaced. Nothing was sent; try again in a minute.; `engine_busy`: The account's engine host has too many calls in flight (256). Nothing was done; try again.; `engine_unavailable`: The account's engine host is not connected to Pipsocket, or disconnected while the call waited. A trade it already had is still settled: look it up.; a stored request whose state is `refused`: the terminal did not send it (for example `busy`, with 1,000 trades already waiting for the trade server). `result` says why. - 504: - `engine_timeout`: The account's engine did not answer within 30 seconds. ### Example ```bash # A new key for each new trade; send the same one to retry it. IDEMPOTENCY_KEY=$(uuidgen) curl -X DELETE "https://api.pipsocket.com/v1/accounts/acc_01m6tx3k9f2qw8r7bznd5yvh4c/orders/881402377" \ -H "Authorization: Bearer $PIPSOCKET_KEY" \ -H "Idempotency-Key: $IDEMPOTENCY_KEY" ``` 200 done: ```json { "message": "The request was completed.", "request": "req_5f0c2a9e41d7b3a8c6e2f190", "result": { "ask": 1.08412, "bid": 1.0841, "comment": "Request executed", "deal": 0, "order": 881402377, "position": 0, "price": 0, "retcode": 10009, "retcode_external": 0, "retcode_name": "TRADE_RETCODE_DONE", "volume": 0 }, "sent": { "action": "remove", "comment": "", "deviation": 0, "expiration": 0, "magic": 0, "order": 881402377, "position": 0, "position_by": 0, "price": 0, "sl": 0, "stoplimit": 0, "symbol": "", "tp": 0, "type": "buy", "type_filling": "fok", "type_time": "gtc", "volume": 0 }, "state": "done" } ``` 200 rejected: ```json { "message": "The request is invalid.", "request": "req_5f0c2a9e41d7b3a8c6e2f190", "result": { "ask": 1.08412, "bid": 1.0841, "comment": "Invalid request", "deal": 0, "order": 0, "position": 0, "price": 0, "retcode": 10013, "retcode_external": 0, "retcode_name": "TRADE_RETCODE_INVALID", "volume": 0 }, "sent": { "action": "remove", "comment": "", "deviation": 0, "expiration": 0, "magic": 0, "order": 881402377, "position": 0, "position_by": 0, "price": 0, "sl": 0, "stoplimit": 0, "symbol": "", "tp": 0, "type": "buy", "type_filling": "fok", "type_time": "gtc", "volume": 0 }, "state": "done" } ``` 202 pending: ```json { "message": "No answer from the trade server yet. The order may still execute; it is not sent again.", "request": "req_5f0c2a9e41d7b3a8c6e2f190", "result": null, "sent": { "action": "remove", "comment": "", "deviation": 0, "expiration": 0, "magic": 0, "order": 881402377, "position": 0, "position_by": 0, "price": 0, "sl": 0, "stoplimit": 0, "symbol": "", "tp": 0, "type": "buy", "type_filling": "fok", "type_time": "gtc", "volume": 0 }, "state": "pending" } ``` --- # Close a position Source: https://docs.pipsocket.com/api/close-a-position Close all or part of an open position. All calls: `https://api.pipsocket.com`, with `Authorization: Bearer `. ## Close a position `POST /v1/accounts/{account}/positions/{position}/close` Closes all or part of an open position: a deal the other way for the volume given, naming the position (`TRADE_ACTION_DEAL` with `position`). ### Path - `account` (string, required): The account's id, `acc_` and 26 characters, as the dashboard shows it. - `position` (integer, required): The position's ticket. ### Headers - `Idempotency-Key` (string, optional): Your own key for this request, 1 to 128 characters. A request with a key the account has used before (in the last 7 days) is not sent: the first request's answer comes back instead, as it stands now. ### Body Closing all or part of a position: a deal the other way naming the position. - `volume` (number, required, MT5 `volume`): Lots to close: the position's whole volume, or part of it. - `type_filling` (enum, required, MT5 `type_filling`): How the closing deal may fill. Required: each symbol allows its own modes (its `filling_modes`). One of: `fok`, `ioc`, `return`, `boc`. - `price` (number, optional, MT5 `price`): Sent as given (0 if left out): brokers with instant or request execution need it, those with market or exchange execution ignore it. - `deviation` (integer, optional, MT5 `deviation`): The largest difference from `price` MT5 accepts, in points, for instant or request execution. - `magic` (integer, optional, MT5 `magic`): Your own number, kept by MT5 on the closing deal. - `comment` (string, optional, MT5 `comment`): Up to 31 characters, kept by MT5 on the closing deal. ### Response - `request` (string): The request's id (`req_...`): look it up with `GET /requests/{request}`. - `state` (enum): A trade request's state: `pending` (sent, no answer yet: never sent again), `done` (MT5 answered: filled, placed or rejected, as `result.retcode` says), `unknown` (no answer within 130 seconds; it becomes `done` if the terminal reports the answer later) or `refused` (the terminal did not send it). One of: `pending`, `done`, `unknown`, `refused`. - `sent` (object): MT5's `MqlTradeRequest`, field for field, exactly as recorded to send to the terminal: the request's `state` and `result` say whether it reached MT5. Fields the call does not use carry MT5's empty values (0, "", `fok`, `gtc`). - `action` (enum, MT5 `action`): What the request does. One of: `deal`, `pending`, `sltp`, `modify`, `remove`, `close_by`. - `symbol` (string, MT5 `symbol`): The symbol, exactly as the broker names it. - `type` (enum, MT5 `type`): The order type. One of: `buy`, `sell`, `buy_limit`, `sell_limit`, `buy_stop`, `sell_stop`, `buy_stop_limit`, `sell_stop_limit`, `close_by`. - `volume` (number, MT5 `volume`): Lots. - `price` (number, MT5 `price`): The price: a pending order's, or the one instant and request execution trade at. - `stoplimit` (number, MT5 `stoplimit`): A stop-limit order's limit price, placed once `price` is reached. - `sl` (number, MT5 `sl`): Stop loss price; 0 for none. - `tp` (number, MT5 `tp`): Take profit price; 0 for none. - `deviation` (integer, MT5 `deviation`): The largest difference from `price` MT5 accepts, in points. - `type_filling` (enum, MT5 `type_filling`): How the order may fill. One of: `fok`, `ioc`, `return`, `boc`. - `type_time` (enum, MT5 `type_time`): How long a pending order lasts. One of: `gtc`, `day`, `specified`, `specified_day`. - `expiration` (integer, MT5 `expiration`): Broker server time, seconds since 1970, as MT5 takes it. - `order` (integer, MT5 `order`): The pending order the request is about (modify, remove). - `position` (integer, MT5 `position`): The position the request is about (close, stops, close by). - `position_by` (integer, MT5 `position_by`): The opposite position, for close by. - `magic` (integer, MT5 `magic`): Your own number, kept by MT5 on the order, its deals and its position. - `comment` (string, MT5 `comment`): Up to 31 characters, kept by MT5 on the order. - `result` (object, or null): MT5's `MqlTradeResult` once `done`; why it was not sent once `refused`; otherwise null. - `message` (string): What the answer means, in a sentence. ### Answers - 200: MT5's answer: the request is `done` (filled, placed or rejected, as the retcode says), or `unknown` for a repeated key whose first request never got an answer. - 202: No answer from the trade server within 5 seconds: the request is `pending` and is never sent again. Look it up to see how it ended. - 400: The ticket in the path is not a whole number. No body. - 401: - `missing_api_key`: No API key: send it as `Authorization: Bearer `.; `invalid_api_key`: The key is not a workspace's current key (a rolled key stops working within about a minute). - 404: - `no_such_account`: No such account, or one the key's workspace doesn't have: the two look the same.; `no_such_position`: The account has no open position with that ticket (read fresh from the terminal). - 422: - `invalid_request`: A field, query parameter or header is missing, malformed or not allowed, or the body is not JSON. Nothing was sent. - 503: - `account_not_connected`: The account's terminal is not connected to the engine (stopped, starting, or restarting). Nothing was sent, except by the kill switch: engaging it still engages it, and may already have deleted pending orders.; `bridge_outdated`: The account's terminal runs an older bridge that can't trade: restart the account to update it. Nothing was sent.; `account_restarting`: The account's terminal is being replaced. Nothing was sent; try again in a minute.; `engine_busy`: The account's engine host has too many calls in flight (256). Nothing was done; try again.; `engine_unavailable`: The account's engine host is not connected to Pipsocket, or disconnected while the call waited. A trade it already had is still settled: look it up.; a stored request whose state is `refused`: the terminal did not send it (for example `busy`, with 1,000 trades already waiting for the trade server). `result` says why. - 504: - `terminal_timeout`: The account's terminal did not answer within 5 seconds.; `engine_timeout`: The account's engine did not answer within 30 seconds. ### Example ```bash # A new key for each new trade; send the same one to retry it. IDEMPOTENCY_KEY=$(uuidgen) curl -X POST "https://api.pipsocket.com/v1/accounts/acc_01m6tx3k9f2qw8r7bznd5yvh4c/positions/881402311/close" \ -H "Authorization: Bearer $PIPSOCKET_KEY" \ -H "Idempotency-Key: $IDEMPOTENCY_KEY" \ -H "Content-Type: application/json" \ -d '{ "type_filling": "ioc", "volume": 0.1 }' ``` 200 done: ```json { "message": "The request was completed.", "request": "req_5f0c2a9e41d7b3a8c6e2f190", "result": { "ask": 1.08412, "bid": 1.0841, "comment": "Request executed", "deal": 771203498, "order": 881402390, "position": 0, "price": 1.0841, "retcode": 10009, "retcode_external": 0, "retcode_name": "TRADE_RETCODE_DONE", "volume": 0.1 }, "sent": { "action": "deal", "comment": "", "deviation": 0, "expiration": 0, "magic": 0, "order": 0, "position": 881402311, "position_by": 0, "price": 0, "sl": 0, "stoplimit": 0, "symbol": "EURUSD", "tp": 0, "type": "sell", "type_filling": "ioc", "type_time": "gtc", "volume": 0.1 }, "state": "done" } ``` 200 rejected: ```json { "message": "The filling mode is not allowed for this symbol.", "request": "req_5f0c2a9e41d7b3a8c6e2f190", "result": { "ask": 1.08412, "bid": 1.0841, "comment": "Unsupported filling mode", "deal": 0, "order": 0, "position": 0, "price": 0, "retcode": 10030, "retcode_external": 0, "retcode_name": "TRADE_RETCODE_INVALID_FILL", "volume": 0 }, "sent": { "action": "deal", "comment": "", "deviation": 0, "expiration": 0, "magic": 0, "order": 0, "position": 881402311, "position_by": 0, "price": 0, "sl": 0, "stoplimit": 0, "symbol": "EURUSD", "tp": 0, "type": "sell", "type_filling": "ioc", "type_time": "gtc", "volume": 0.1 }, "state": "done" } ``` 202 pending: ```json { "message": "No answer from the trade server yet. The order may still execute; it is not sent again.", "request": "req_5f0c2a9e41d7b3a8c6e2f190", "result": null, "sent": { "action": "deal", "comment": "", "deviation": 0, "expiration": 0, "magic": 0, "order": 0, "position": 881402311, "position_by": 0, "price": 0, "sl": 0, "stoplimit": 0, "symbol": "EURUSD", "tp": 0, "type": "sell", "type_filling": "ioc", "type_time": "gtc", "volume": 0.1 }, "state": "pending" } ``` --- # Close by Source: https://docs.pipsocket.com/api/close-by Close a position against an opposite one. All calls: `https://api.pipsocket.com`, with `Authorization: Bearer `. ## Close by an opposite position `POST /v1/accounts/{account}/positions/{position}/close-by` Closes a position against an opposite position on the same symbol (`TRADE_ACTION_CLOSE_BY`). ### Path - `account` (string, required): The account's id, `acc_` and 26 characters, as the dashboard shows it. - `position` (integer, required): The position's ticket. ### Headers - `Idempotency-Key` (string, optional): Your own key for this request, 1 to 128 characters. A request with a key the account has used before (in the last 7 days) is not sent: the first request's answer comes back instead, as it stands now. ### Body Closing a position against an opposite one on the same symbol. - `position_by` (integer, required, MT5 `position_by`): The opposite position's ticket. ### Response - `request` (string): The request's id (`req_...`): look it up with `GET /requests/{request}`. - `state` (enum): A trade request's state: `pending` (sent, no answer yet: never sent again), `done` (MT5 answered: filled, placed or rejected, as `result.retcode` says), `unknown` (no answer within 130 seconds; it becomes `done` if the terminal reports the answer later) or `refused` (the terminal did not send it). One of: `pending`, `done`, `unknown`, `refused`. - `sent` (object): MT5's `MqlTradeRequest`, field for field, exactly as recorded to send to the terminal: the request's `state` and `result` say whether it reached MT5. Fields the call does not use carry MT5's empty values (0, "", `fok`, `gtc`). - `action` (enum, MT5 `action`): What the request does. One of: `deal`, `pending`, `sltp`, `modify`, `remove`, `close_by`. - `symbol` (string, MT5 `symbol`): The symbol, exactly as the broker names it. - `type` (enum, MT5 `type`): The order type. One of: `buy`, `sell`, `buy_limit`, `sell_limit`, `buy_stop`, `sell_stop`, `buy_stop_limit`, `sell_stop_limit`, `close_by`. - `volume` (number, MT5 `volume`): Lots. - `price` (number, MT5 `price`): The price: a pending order's, or the one instant and request execution trade at. - `stoplimit` (number, MT5 `stoplimit`): A stop-limit order's limit price, placed once `price` is reached. - `sl` (number, MT5 `sl`): Stop loss price; 0 for none. - `tp` (number, MT5 `tp`): Take profit price; 0 for none. - `deviation` (integer, MT5 `deviation`): The largest difference from `price` MT5 accepts, in points. - `type_filling` (enum, MT5 `type_filling`): How the order may fill. One of: `fok`, `ioc`, `return`, `boc`. - `type_time` (enum, MT5 `type_time`): How long a pending order lasts. One of: `gtc`, `day`, `specified`, `specified_day`. - `expiration` (integer, MT5 `expiration`): Broker server time, seconds since 1970, as MT5 takes it. - `order` (integer, MT5 `order`): The pending order the request is about (modify, remove). - `position` (integer, MT5 `position`): The position the request is about (close, stops, close by). - `position_by` (integer, MT5 `position_by`): The opposite position, for close by. - `magic` (integer, MT5 `magic`): Your own number, kept by MT5 on the order, its deals and its position. - `comment` (string, MT5 `comment`): Up to 31 characters, kept by MT5 on the order. - `result` (object, or null): MT5's `MqlTradeResult` once `done`; why it was not sent once `refused`; otherwise null. - `message` (string): What the answer means, in a sentence. ### Answers - 200: MT5's answer: the request is `done` (filled, placed or rejected, as the retcode says), or `unknown` for a repeated key whose first request never got an answer. - 202: No answer from the trade server within 5 seconds: the request is `pending` and is never sent again. Look it up to see how it ended. - 400: The ticket in the path is not a whole number. No body. - 401: - `missing_api_key`: No API key: send it as `Authorization: Bearer `.; `invalid_api_key`: The key is not a workspace's current key (a rolled key stops working within about a minute). - 404: - `no_such_account`: No such account, or one the key's workspace doesn't have: the two look the same.; `no_such_position`: The account has no open position with that ticket (read fresh from the terminal). - 422: - `invalid_request`: A field, query parameter or header is missing, malformed or not allowed, or the body is not JSON. Nothing was sent. - 503: - `account_not_connected`: The account's terminal is not connected to the engine (stopped, starting, or restarting). Nothing was sent, except by the kill switch: engaging it still engages it, and may already have deleted pending orders.; `bridge_outdated`: The account's terminal runs an older bridge that can't trade: restart the account to update it. Nothing was sent.; `account_restarting`: The account's terminal is being replaced. Nothing was sent; try again in a minute.; `engine_busy`: The account's engine host has too many calls in flight (256). Nothing was done; try again.; `engine_unavailable`: The account's engine host is not connected to Pipsocket, or disconnected while the call waited. A trade it already had is still settled: look it up.; a stored request whose state is `refused`: the terminal did not send it (for example `busy`, with 1,000 trades already waiting for the trade server). `result` says why. - 504: - `terminal_timeout`: The account's terminal did not answer within 5 seconds.; `engine_timeout`: The account's engine did not answer within 30 seconds. ### Example ```bash # A new key for each new trade; send the same one to retry it. IDEMPOTENCY_KEY=$(uuidgen) curl -X POST "https://api.pipsocket.com/v1/accounts/acc_01m6tx3k9f2qw8r7bznd5yvh4c/positions/881402311/close-by" \ -H "Authorization: Bearer $PIPSOCKET_KEY" \ -H "Idempotency-Key: $IDEMPOTENCY_KEY" \ -H "Content-Type: application/json" \ -d '{ "position_by": 881402350 }' ``` 200 done: ```json { "message": "The request was completed.", "request": "req_5f0c2a9e41d7b3a8c6e2f190", "result": { "ask": 1.08412, "bid": 1.0841, "comment": "Request executed", "deal": 771203499, "order": 881402391, "position": 0, "price": 1.0841, "retcode": 10009, "retcode_external": 0, "retcode_name": "TRADE_RETCODE_DONE", "volume": 0.1 }, "sent": { "action": "close_by", "comment": "", "deviation": 0, "expiration": 0, "magic": 0, "order": 0, "position": 881402311, "position_by": 881402350, "price": 0, "sl": 0, "stoplimit": 0, "symbol": "EURUSD", "tp": 0, "type": "close_by", "type_filling": "fok", "type_time": "gtc", "volume": 0 }, "state": "done" } ``` 200 rejected: ```json { "message": "The request is invalid.", "request": "req_5f0c2a9e41d7b3a8c6e2f190", "result": { "ask": 1.08412, "bid": 1.0841, "comment": "Invalid request", "deal": 0, "order": 0, "position": 0, "price": 0, "retcode": 10013, "retcode_external": 0, "retcode_name": "TRADE_RETCODE_INVALID", "volume": 0 }, "sent": { "action": "close_by", "comment": "", "deviation": 0, "expiration": 0, "magic": 0, "order": 0, "position": 881402311, "position_by": 881402350, "price": 0, "sl": 0, "stoplimit": 0, "symbol": "EURUSD", "tp": 0, "type": "close_by", "type_filling": "fok", "type_time": "gtc", "volume": 0 }, "state": "done" } ``` 202 pending: ```json { "message": "No answer from the trade server yet. The order may still execute; it is not sent again.", "request": "req_5f0c2a9e41d7b3a8c6e2f190", "result": null, "sent": { "action": "close_by", "comment": "", "deviation": 0, "expiration": 0, "magic": 0, "order": 0, "position": 881402311, "position_by": 881402350, "price": 0, "sl": 0, "stoplimit": 0, "symbol": "EURUSD", "tp": 0, "type": "close_by", "type_filling": "fok", "type_time": "gtc", "volume": 0 }, "state": "pending" } ``` --- # Set stops Source: https://docs.pipsocket.com/api/set-stops A position's stop loss and take profit. All calls: `https://api.pipsocket.com`, with `Authorization: Bearer `. ## Set stop loss and take profit `PATCH /v1/accounts/{account}/positions/{position}` Sets an open position's stop loss and take profit (`TRADE_ACTION_SLTP`). Both are given; 0 removes one. ### Path - `account` (string, required): The account's id, `acc_` and 26 characters, as the dashboard shows it. - `position` (integer, required): The position's ticket. ### Headers - `Idempotency-Key` (string, optional): Your own key for this request, 1 to 128 characters. A request with a key the account has used before (in the last 7 days) is not sent: the first request's answer comes back instead, as it stands now. ### Body A position's stop loss and take profit. Both are required, as MT5 sets both: give the one you keep as it is. - `sl` (number, required, MT5 `sl`): Stop loss price; 0 removes it. - `tp` (number, required, MT5 `tp`): Take profit price; 0 removes it. ### Response - `request` (string): The request's id (`req_...`): look it up with `GET /requests/{request}`. - `state` (enum): A trade request's state: `pending` (sent, no answer yet: never sent again), `done` (MT5 answered: filled, placed or rejected, as `result.retcode` says), `unknown` (no answer within 130 seconds; it becomes `done` if the terminal reports the answer later) or `refused` (the terminal did not send it). One of: `pending`, `done`, `unknown`, `refused`. - `sent` (object): MT5's `MqlTradeRequest`, field for field, exactly as recorded to send to the terminal: the request's `state` and `result` say whether it reached MT5. Fields the call does not use carry MT5's empty values (0, "", `fok`, `gtc`). - `action` (enum, MT5 `action`): What the request does. One of: `deal`, `pending`, `sltp`, `modify`, `remove`, `close_by`. - `symbol` (string, MT5 `symbol`): The symbol, exactly as the broker names it. - `type` (enum, MT5 `type`): The order type. One of: `buy`, `sell`, `buy_limit`, `sell_limit`, `buy_stop`, `sell_stop`, `buy_stop_limit`, `sell_stop_limit`, `close_by`. - `volume` (number, MT5 `volume`): Lots. - `price` (number, MT5 `price`): The price: a pending order's, or the one instant and request execution trade at. - `stoplimit` (number, MT5 `stoplimit`): A stop-limit order's limit price, placed once `price` is reached. - `sl` (number, MT5 `sl`): Stop loss price; 0 for none. - `tp` (number, MT5 `tp`): Take profit price; 0 for none. - `deviation` (integer, MT5 `deviation`): The largest difference from `price` MT5 accepts, in points. - `type_filling` (enum, MT5 `type_filling`): How the order may fill. One of: `fok`, `ioc`, `return`, `boc`. - `type_time` (enum, MT5 `type_time`): How long a pending order lasts. One of: `gtc`, `day`, `specified`, `specified_day`. - `expiration` (integer, MT5 `expiration`): Broker server time, seconds since 1970, as MT5 takes it. - `order` (integer, MT5 `order`): The pending order the request is about (modify, remove). - `position` (integer, MT5 `position`): The position the request is about (close, stops, close by). - `position_by` (integer, MT5 `position_by`): The opposite position, for close by. - `magic` (integer, MT5 `magic`): Your own number, kept by MT5 on the order, its deals and its position. - `comment` (string, MT5 `comment`): Up to 31 characters, kept by MT5 on the order. - `result` (object, or null): MT5's `MqlTradeResult` once `done`; why it was not sent once `refused`; otherwise null. - `message` (string): What the answer means, in a sentence. ### Answers - 200: MT5's answer: the request is `done` (filled, placed or rejected, as the retcode says), or `unknown` for a repeated key whose first request never got an answer. - 202: No answer from the trade server within 5 seconds: the request is `pending` and is never sent again. Look it up to see how it ended. - 400: The ticket in the path is not a whole number. No body. - 401: - `missing_api_key`: No API key: send it as `Authorization: Bearer `.; `invalid_api_key`: The key is not a workspace's current key (a rolled key stops working within about a minute). - 404: - `no_such_account`: No such account, or one the key's workspace doesn't have: the two look the same.; `no_such_position`: The account has no open position with that ticket (read fresh from the terminal). - 422: - `invalid_request`: A field, query parameter or header is missing, malformed or not allowed, or the body is not JSON. Nothing was sent. - 503: - `account_not_connected`: The account's terminal is not connected to the engine (stopped, starting, or restarting). Nothing was sent, except by the kill switch: engaging it still engages it, and may already have deleted pending orders.; `bridge_outdated`: The account's terminal runs an older bridge that can't trade: restart the account to update it. Nothing was sent.; `account_restarting`: The account's terminal is being replaced. Nothing was sent; try again in a minute.; `engine_busy`: The account's engine host has too many calls in flight (256). Nothing was done; try again.; `engine_unavailable`: The account's engine host is not connected to Pipsocket, or disconnected while the call waited. A trade it already had is still settled: look it up.; a stored request whose state is `refused`: the terminal did not send it (for example `busy`, with 1,000 trades already waiting for the trade server). `result` says why. - 504: - `terminal_timeout`: The account's terminal did not answer within 5 seconds.; `engine_timeout`: The account's engine did not answer within 30 seconds. ### Example ```bash # A new key for each new trade; send the same one to retry it. IDEMPOTENCY_KEY=$(uuidgen) curl -X PATCH "https://api.pipsocket.com/v1/accounts/acc_01m6tx3k9f2qw8r7bznd5yvh4c/positions/881402311" \ -H "Authorization: Bearer $PIPSOCKET_KEY" \ -H "Idempotency-Key: $IDEMPOTENCY_KEY" \ -H "Content-Type: application/json" \ -d '{ "sl": 1.079, "tp": 1.09 }' ``` 200 done: ```json { "message": "The request was completed.", "request": "req_5f0c2a9e41d7b3a8c6e2f190", "result": { "ask": 1.08412, "bid": 1.0841, "comment": "Request executed", "deal": 0, "order": 0, "position": 0, "price": 0, "retcode": 10009, "retcode_external": 0, "retcode_name": "TRADE_RETCODE_DONE", "volume": 0 }, "sent": { "action": "sltp", "comment": "", "deviation": 0, "expiration": 0, "magic": 0, "order": 0, "position": 881402311, "position_by": 0, "price": 0, "sl": 1.079, "stoplimit": 0, "symbol": "EURUSD", "tp": 1.09, "type": "buy", "type_filling": "fok", "type_time": "gtc", "volume": 0 }, "state": "done" } ``` 200 rejected: ```json { "message": "The stop loss or take profit is invalid for this symbol or too close to the price.", "request": "req_5f0c2a9e41d7b3a8c6e2f190", "result": { "ask": 1.08412, "bid": 1.0841, "comment": "Invalid stops", "deal": 0, "order": 0, "position": 0, "price": 0, "retcode": 10016, "retcode_external": 0, "retcode_name": "TRADE_RETCODE_INVALID_STOPS", "volume": 0 }, "sent": { "action": "sltp", "comment": "", "deviation": 0, "expiration": 0, "magic": 0, "order": 0, "position": 881402311, "position_by": 0, "price": 0, "sl": 1.079, "stoplimit": 0, "symbol": "EURUSD", "tp": 1.09, "type": "buy", "type_filling": "fok", "type_time": "gtc", "volume": 0 }, "state": "done" } ``` 202 pending: ```json { "message": "No answer from the trade server yet. The order may still execute; it is not sent again.", "request": "req_5f0c2a9e41d7b3a8c6e2f190", "result": null, "sent": { "action": "sltp", "comment": "", "deviation": 0, "expiration": 0, "magic": 0, "order": 0, "position": 881402311, "position_by": 0, "price": 0, "sl": 1.079, "stoplimit": 0, "symbol": "EURUSD", "tp": 1.09, "type": "buy", "type_filling": "fok", "type_time": "gtc", "volume": 0 }, "state": "pending" } ``` --- # Account Source: https://docs.pipsocket.com/api/account Login, status, balance, equity and margin. All calls: `https://api.pipsocket.com`, with `Authorization: Bearer `. ## Get the account `GET /v1/accounts/{account}` The account's login, status and connection, and the balance, equity and margin from its terminal's last report (once a second). Read from the engine, not the terminal, so it answers while the terminal is away. ### Path - `account` (string, required): The account's id, `acc_` and 26 characters, as the dashboard shows it. ### Response - `id` (string): The account's id. - `login` (integer): The MT5 login. - `server` (string): The broker's trade server. - `status` (string): What the engine knows of the account's terminal: `starting`, `connected`, `disconnected`, `unreachable` (the broker's server can't be reached; it keeps trying), `stopped`, or a status someone has to act on: `auth_failed` (the broker refused the login), `server_not_found`, `login_unknown` or `refused`. - `connected` (boolean): Whether the terminal reports a connection to the trade server. - `trade_allowed` (boolean, or null): Whether MT5 lets this terminal trade: the terminal, the account and automated trading all allow it. False for an investor (read-only) login. - `company` (string, or null): The broker. - `currency` (string, or null): The account's currency. - `leverage` (integer, or null): - `margin_mode` (string, or null): `hedging`, `netting` or `exchange`. - `trade_mode` (string, or null): `demo`, `contest` or `real`. - `balance` (number, or null): - `equity` (number, or null): - `credit` (number, or null): - `margin` (number, or null): - `margin_free` (number, or null): - `server_time` (integer, or null): The trade server's time at the last report: broker server time, seconds since 1970. - `kill_switch` (object): Whether the account's kill switch is engaged. - `engaged` (boolean): - `since` (integer, or null): When it was engaged: seconds since 1970 (UTC). Null when it is not engaged. - `deviation` (integer, or null): The deviation, in points, its closing deals carry. Null when it is not engaged. ### Answers - 200: The account. - 401: - `missing_api_key`: No API key: send it as `Authorization: Bearer `.; `invalid_api_key`: The key is not a workspace's current key (a rolled key stops working within about a minute). - 404: - `no_such_account`: No such account, or one the key's workspace doesn't have: the two look the same. - 503: - `engine_busy`: The account's engine host has too many calls in flight (256). Nothing was done; try again.; `engine_unavailable`: The account's engine host is not connected to Pipsocket, or disconnected while the call waited. A trade it already had is still settled: look it up. - 504: - `engine_timeout`: The account's engine did not answer within 30 seconds. ### Example ```bash curl "https://api.pipsocket.com/v1/accounts/acc_01m6tx3k9f2qw8r7bznd5yvh4c" \ -H "Authorization: Bearer $PIPSOCKET_KEY" ``` 200 connected: ```json { "balance": 10000, "company": "FBS Markets Inc.", "connected": true, "credit": 0, "currency": "USD", "equity": 10012.4, "id": "acc_01m6tx3k9f2qw8r7bznd5yvh4c", "kill_switch": { "deviation": null, "engaged": false, "since": null }, "leverage": 500, "login": 5058427372, "margin": 21.68, "margin_free": 9990.72, "margin_mode": "hedging", "server": "FBS-Demo", "server_time": 1794067825, "status": "connected", "trade_allowed": true, "trade_mode": "demo" } ``` --- # Positions Source: https://docs.pipsocket.com/api/positions Open positions, read fresh from the terminal. All calls: `https://api.pipsocket.com`, with `Authorization: Bearer `. ## List open positions `GET /v1/accounts/{account}/positions` The account's open positions, read fresh from its terminal. ### Path - `account` (string, required): The account's id, `acc_` and 26 characters, as the dashboard shows it. ### Response A list of: - `ticket` (integer, MT5 `POSITION_TICKET`): The position's ticket: use it to close the position or set its stops. - `identifier` (integer, MT5 `POSITION_IDENTIFIER`): The position's id, which stays the same if the broker changes the ticket. - `symbol` (string, MT5 `POSITION_SYMBOL`): - `type` (enum): `buy` or `sell` (MT5's `POSITION_TYPE`). One of: `buy`, `sell`. - `volume` (number, MT5 `POSITION_VOLUME`): - `price_open` (number, MT5 `POSITION_PRICE_OPEN`): - `sl` (number, MT5 `POSITION_SL`): - `tp` (number, MT5 `POSITION_TP`): - `magic` (integer, MT5 `POSITION_MAGIC`): - `comment` (string, MT5 `POSITION_COMMENT`): - `time_msc` (integer, MT5 `POSITION_TIME_MSC`): When it was opened: broker server time, milliseconds since 1970. ### Answers - 200: Every open position. - 401: - `missing_api_key`: No API key: send it as `Authorization: Bearer `.; `invalid_api_key`: The key is not a workspace's current key (a rolled key stops working within about a minute). - 404: - `no_such_account`: No such account, or one the key's workspace doesn't have: the two look the same. - 503: - `account_not_connected`: The account's terminal is not connected to the engine (stopped, starting, or restarting). Nothing was sent, except by the kill switch: engaging it still engages it, and may already have deleted pending orders.; `engine_busy`: The account's engine host has too many calls in flight (256). Nothing was done; try again.; `engine_unavailable`: The account's engine host is not connected to Pipsocket, or disconnected while the call waited. A trade it already had is still settled: look it up. - 504: - `terminal_timeout`: The account's terminal did not answer within 5 seconds.; `engine_timeout`: The account's engine did not answer within 30 seconds. ### Example ```bash curl "https://api.pipsocket.com/v1/accounts/acc_01m6tx3k9f2qw8r7bznd5yvh4c/positions" \ -H "Authorization: Bearer $PIPSOCKET_KEY" ``` 200 positions: ```json [ { "comment": "", "identifier": 881402311, "magic": 0, "price_open": 1.08412, "sl": 1.079, "symbol": "EURUSD", "ticket": 881402311, "time_msc": 1794067801211, "tp": 0, "type": "buy", "volume": 0.1 } ] ``` --- # Pending orders Source: https://docs.pipsocket.com/api/pending-orders Pending orders, read fresh from the terminal. All calls: `https://api.pipsocket.com`, with `Authorization: Bearer `. ## List pending orders `GET /v1/accounts/{account}/orders` The account's pending orders, read fresh from its terminal. ### Path - `account` (string, required): The account's id, `acc_` and 26 characters, as the dashboard shows it. ### Response A list of: - `ticket` (integer, MT5 `ORDER_TICKET`): - `symbol` (string, MT5 `ORDER_SYMBOL`): - `type` (enum, or null, MT5 `ORDER_TYPE`): MT5's `ENUM_ORDER_TYPE`: `buy` and `sell` are market orders (`ORDER_TYPE_BUY`, `ORDER_TYPE_SELL`); `buy_limit`, `sell_limit`, `buy_stop`, `sell_stop`, `buy_stop_limit` and `sell_stop_limit` are pending orders (`ORDER_TYPE_BUY_LIMIT` and so on); `close_by` is `ORDER_TYPE_CLOSE_BY`. One of: `buy`, `sell`, `buy_limit`, `sell_limit`, `buy_stop`, `sell_stop`, `buy_stop_limit`, `sell_stop_limit`, `close_by`. - `volume_initial` (number, MT5 `ORDER_VOLUME_INITIAL`): - `volume_current` (number, MT5 `ORDER_VOLUME_CURRENT`): - `price_open` (number, MT5 `ORDER_PRICE_OPEN`): - `sl` (number, MT5 `ORDER_SL`): - `tp` (number, MT5 `ORDER_TP`): - `magic` (integer, MT5 `ORDER_MAGIC`): - `comment` (string, MT5 `ORDER_COMMENT`): - `position` (integer, MT5 `ORDER_POSITION_ID`): The position the order belongs to, if any. ### Answers - 200: Every pending order. - 401: - `missing_api_key`: No API key: send it as `Authorization: Bearer `.; `invalid_api_key`: The key is not a workspace's current key (a rolled key stops working within about a minute). - 404: - `no_such_account`: No such account, or one the key's workspace doesn't have: the two look the same. - 503: - `account_not_connected`: The account's terminal is not connected to the engine (stopped, starting, or restarting). Nothing was sent, except by the kill switch: engaging it still engages it, and may already have deleted pending orders.; `engine_busy`: The account's engine host has too many calls in flight (256). Nothing was done; try again.; `engine_unavailable`: The account's engine host is not connected to Pipsocket, or disconnected while the call waited. A trade it already had is still settled: look it up. - 504: - `terminal_timeout`: The account's terminal did not answer within 5 seconds.; `engine_timeout`: The account's engine did not answer within 30 seconds. ### Example ```bash curl "https://api.pipsocket.com/v1/accounts/acc_01m6tx3k9f2qw8r7bznd5yvh4c/orders" \ -H "Authorization: Bearer $PIPSOCKET_KEY" ``` 200 orders: ```json [ { "comment": "", "magic": 0, "position": 0, "price_open": 1.075, "sl": 0, "symbol": "EURUSD", "ticket": 881402377, "tp": 0, "type": "buy_limit", "volume_current": 0.1, "volume_initial": 0.1 } ] ``` --- # Deal and order history Source: https://docs.pipsocket.com/api/history Deals and past orders in a time range. All calls: `https://api.pipsocket.com`, with `Authorization: Bearer `. ## List deals `GET /v1/accounts/{account}/history/deals` The account's deals in a time range (MT5's `HistorySelect`), read fresh from its terminal. ### Path - `account` (string, required): The account's id, `acc_` and 26 characters, as the dashboard shows it. ### Query - `from` (integer, required): The range's start: broker server time, seconds since 1970, included. - `to` (integer, required): The range's end: broker server time, seconds since 1970, included. Not before `from`. ### Response A list of: - `ticket` (integer, MT5 `DEAL_TICKET`): - `order` (integer, MT5 `DEAL_ORDER`): The order that made the deal. - `position` (integer, MT5 `DEAL_POSITION_ID`): The position's id (`identifier`). - `symbol` (string, MT5 `DEAL_SYMBOL`): - `type` (enum, or null): MT5's `DEAL_TYPE`: `buy`, `sell`, or a balance operation. One of: `buy`, `sell`, `balance`, `credit`, `charge`, `correction`, `bonus`, `commission`, `commission_daily`, `commission_monthly`, `commission_agent_daily`, `commission_agent_monthly`, `interest`, `buy_canceled`, `sell_canceled`, `dividend`, `dividend_franked`, `tax`. - `entry` (enum): MT5's `DEAL_ENTRY`: `in` opens or adds, `out` closes, `inout` reverses, `out_by` closes by an opposite position. One of: `in`, `out`, `inout`, `out_by`. - `reason` (enum): MT5's `DEAL_REASON`: who or what made the deal (`expert` for the API, `sl`, `tp`, `so` for a stop out). One of: `client`, `mobile`, `web`, `expert`, `sl`, `tp`, `so`, `other`. - `volume` (number, MT5 `DEAL_VOLUME`): - `price` (number, MT5 `DEAL_PRICE`): - `profit` (number, MT5 `DEAL_PROFIT`): - `commission` (number, MT5 `DEAL_COMMISSION`): - `swap` (number, MT5 `DEAL_SWAP`): - `fee` (number, MT5 `DEAL_FEE`): - `magic` (integer, MT5 `DEAL_MAGIC`): - `comment` (string, MT5 `DEAL_COMMENT`): - `time_msc` (integer, MT5 `DEAL_TIME_MSC`): Broker server time, milliseconds since 1970. ### Answers - 200: Every deal in the range. - 401: - `missing_api_key`: No API key: send it as `Authorization: Bearer `.; `invalid_api_key`: The key is not a workspace's current key (a rolled key stops working within about a minute). - 404: - `no_such_account`: No such account, or one the key's workspace doesn't have: the two look the same. - 422: - `invalid_request`: A field, query parameter or header is missing, malformed or not allowed, or the body is not JSON. Nothing was sent.; `range_too_large`: The history range holds more than one answer can carry: ask for a shorter range. - 503: - `account_not_connected`: The account's terminal is not connected to the engine (stopped, starting, or restarting). Nothing was sent, except by the kill switch: engaging it still engages it, and may already have deleted pending orders.; `bad_command`: The terminal refused the command, for example a negative `expiration`, or a history range MT5 can't select.; `terminal_error`: The terminal did not give the answer asked for.; `engine_busy`: The account's engine host has too many calls in flight (256). Nothing was done; try again.; `engine_unavailable`: The account's engine host is not connected to Pipsocket, or disconnected while the call waited. A trade it already had is still settled: look it up. - 504: - `terminal_timeout`: The account's terminal did not answer within 5 seconds.; `engine_timeout`: The account's engine did not answer within 30 seconds. ### Example ```bash curl "https://api.pipsocket.com/v1/accounts/acc_01m6tx3k9f2qw8r7bznd5yvh4c/history/deals?from=1794009600&to=1794095999" \ -H "Authorization: Bearer $PIPSOCKET_KEY" ``` 200 deals: ```json [ { "comment": "", "commission": -0.35, "entry": "in", "fee": 0, "magic": 0, "order": 881402311, "position": 881402311, "price": 1.08412, "profit": 0, "reason": "expert", "swap": 0, "symbol": "EURUSD", "ticket": 771203455, "time_msc": 1794067801211, "type": "buy", "volume": 0.1 }, { "comment": "[sl 1.07900]", "commission": -0.35, "entry": "out", "fee": 0, "magic": 0, "order": 881402390, "position": 881402311, "price": 1.079, "profit": -51.2, "reason": "sl", "swap": 0, "symbol": "EURUSD", "ticket": 771203498, "time_msc": 1794071102540, "type": "sell", "volume": 0.1 } ] ``` ## List past orders `GET /v1/accounts/{account}/history/orders` The account's orders no longer pending in a time range (MT5's `HistorySelect`), with their final state, read fresh from its terminal. ### Path - `account` (string, required): The account's id, `acc_` and 26 characters, as the dashboard shows it. ### Query - `from` (integer, required): The range's start: broker server time, seconds since 1970, included. - `to` (integer, required): The range's end: broker server time, seconds since 1970, included. Not before `from`. ### Response A list of: - `ticket` (integer, MT5 `ORDER_TICKET`): - `symbol` (string, MT5 `ORDER_SYMBOL`): - `type` (enum, or null, MT5 `ORDER_TYPE`): MT5's `ENUM_ORDER_TYPE`: `buy` and `sell` are market orders (`ORDER_TYPE_BUY`, `ORDER_TYPE_SELL`); `buy_limit`, `sell_limit`, `buy_stop`, `sell_stop`, `buy_stop_limit` and `sell_stop_limit` are pending orders (`ORDER_TYPE_BUY_LIMIT` and so on); `close_by` is `ORDER_TYPE_CLOSE_BY`. One of: `buy`, `sell`, `buy_limit`, `sell_limit`, `buy_stop`, `sell_stop`, `buy_stop_limit`, `sell_stop_limit`, `close_by`. - `state` (enum, or null): MT5's `ORDER_STATE`. One of: `started`, `placed`, `canceled`, `partial`, `filled`, `rejected`, `expired`, `request_add`, `request_modify`, `request_cancel`. - `volume_initial` (number, MT5 `ORDER_VOLUME_INITIAL`): - `volume_current` (number, MT5 `ORDER_VOLUME_CURRENT`): - `price_open` (number, MT5 `ORDER_PRICE_OPEN`): - `magic` (integer, MT5 `ORDER_MAGIC`): - `comment` (string, MT5 `ORDER_COMMENT`): - `position` (integer, MT5 `ORDER_POSITION_ID`): - `time_setup_msc` (integer, MT5 `ORDER_TIME_SETUP_MSC`): Broker server time, milliseconds since 1970. - `time_done_msc` (integer, MT5 `ORDER_TIME_DONE_MSC`): Broker server time, milliseconds since 1970. ### Answers - 200: Every order in the range. - 401: - `missing_api_key`: No API key: send it as `Authorization: Bearer `.; `invalid_api_key`: The key is not a workspace's current key (a rolled key stops working within about a minute). - 404: - `no_such_account`: No such account, or one the key's workspace doesn't have: the two look the same. - 422: - `invalid_request`: A field, query parameter or header is missing, malformed or not allowed, or the body is not JSON. Nothing was sent.; `range_too_large`: The history range holds more than one answer can carry: ask for a shorter range. - 503: - `account_not_connected`: The account's terminal is not connected to the engine (stopped, starting, or restarting). Nothing was sent, except by the kill switch: engaging it still engages it, and may already have deleted pending orders.; `bad_command`: The terminal refused the command, for example a negative `expiration`, or a history range MT5 can't select.; `terminal_error`: The terminal did not give the answer asked for.; `engine_busy`: The account's engine host has too many calls in flight (256). Nothing was done; try again.; `engine_unavailable`: The account's engine host is not connected to Pipsocket, or disconnected while the call waited. A trade it already had is still settled: look it up. - 504: - `terminal_timeout`: The account's terminal did not answer within 5 seconds.; `engine_timeout`: The account's engine did not answer within 30 seconds. ### Example ```bash curl "https://api.pipsocket.com/v1/accounts/acc_01m6tx3k9f2qw8r7bznd5yvh4c/history/orders?from=1794009600&to=1794095999" \ -H "Authorization: Bearer $PIPSOCKET_KEY" ``` 200 orders: ```json [ { "comment": "", "magic": 0, "position": 881402311, "price_open": 0, "state": "filled", "symbol": "EURUSD", "ticket": 881402311, "time_done_msc": 1794067801211, "time_setup_msc": 1794067801150, "type": "buy", "volume_current": 0, "volume_initial": 0.1 } ] ``` --- # Symbols and prices Source: https://docs.pipsocket.com/api/symbols The broker's symbols, their specifications and prices. All calls: `https://api.pipsocket.com`, with `Authorization: Bearer `. ## List symbols `GET /v1/accounts/{account}/symbols` Every symbol the broker offers the account, in Market Watch or not, read from the terminal. Large brokers list thousands; read a symbol for its full specification. ### Path - `account` (string, required): The account's id, `acc_` and 26 characters, as the dashboard shows it. ### Response A list of: - `name` (string, MT5 `SYMBOL_NAME`): - `description` (string, MT5 `SYMBOL_DESCRIPTION`): - `path` (string, MT5 `SYMBOL_PATH`): Where it sits in the broker's symbol tree. - `available` (boolean): Whether the terminal could read its properties. - `digits` (integer, MT5 `SYMBOL_DIGITS`): - `contract_size` (number, MT5 `SYMBOL_TRADE_CONTRACT_SIZE`): - `currency_base` (string, MT5 `SYMBOL_CURRENCY_BASE`): - `currency_profit` (string, MT5 `SYMBOL_CURRENCY_PROFIT`): - `currency_margin` (string, MT5 `SYMBOL_CURRENCY_MARGIN`): - `trading` (enum, or null): MT5's `SYMBOL_TRADE_MODE`: whether and which way the symbol can be traded. One of: `disabled`, `long_only`, `short_only`, `close_only`, `full`. - `volume_min` (number, MT5 `SYMBOL_VOLUME_MIN`): - `volume_max` (number, MT5 `SYMBOL_VOLUME_MAX`): - `volume_step` (number, MT5 `SYMBOL_VOLUME_STEP`): - `in_market_watch` (boolean, MT5 `SYMBOL_SELECT`): Whether it is in the terminal's Market Watch. ### Answers - 200: Every symbol. - 401: - `missing_api_key`: No API key: send it as `Authorization: Bearer `.; `invalid_api_key`: The key is not a workspace's current key (a rolled key stops working within about a minute). - 404: - `no_such_account`: No such account, or one the key's workspace doesn't have: the two look the same. - 503: - `account_not_connected`: The account's terminal is not connected to the engine (stopped, starting, or restarting). Nothing was sent, except by the kill switch: engaging it still engages it, and may already have deleted pending orders.; `terminal_error`: The terminal did not give the answer asked for.; `symbol_too_large`: One symbol's entry is too large for the terminal to list.; `engine_busy`: The account's engine host has too many calls in flight (256). Nothing was done; try again.; `engine_unavailable`: The account's engine host is not connected to Pipsocket, or disconnected while the call waited. A trade it already had is still settled: look it up. - 504: - `terminal_timeout`: The account's terminal did not answer within 5 seconds.; `engine_timeout`: The account's engine did not answer within 30 seconds. ### Example ```bash curl "https://api.pipsocket.com/v1/accounts/acc_01m6tx3k9f2qw8r7bznd5yvh4c/symbols" \ -H "Authorization: Bearer $PIPSOCKET_KEY" ``` 200 symbols: ```json [ { "available": true, "contract_size": 100000, "currency_base": "EUR", "currency_margin": "EUR", "currency_profit": "USD", "description": "Euro vs US Dollar", "digits": 5, "in_market_watch": true, "name": "EURUSD", "path": "Forex\\EURUSD", "trading": "full", "volume_max": 500, "volume_min": 0.01, "volume_step": 0.01 } ] ``` ## Get a symbol `GET /v1/accounts/{account}/symbols/{symbol}` A symbol's specification from the terminal: digits, contract size, volume limits, stops and freeze levels, and the filling modes, execution, order types and expirations it allows. ### Path - `account` (string, required): The account's id, `acc_` and 26 characters, as the dashboard shows it. - `symbol` (string, required): The symbol exactly as the broker names it, such as `EURUSD`. ### Response - `name` (string, MT5 `SYMBOL_NAME`): - `available` (boolean): Whether the terminal could read its properties; when false the rest are empty values. - `description` (string, MT5 `SYMBOL_DESCRIPTION`): - `digits` (integer, MT5 `SYMBOL_DIGITS`): - `point` (number, MT5 `SYMBOL_POINT`): - `tick_size` (number, MT5 `SYMBOL_TRADE_TICK_SIZE`): - `tick_value` (number, MT5 `SYMBOL_TRADE_TICK_VALUE`): - `contract_size` (number, MT5 `SYMBOL_TRADE_CONTRACT_SIZE`): - `volume_min` (number, MT5 `SYMBOL_VOLUME_MIN`): - `volume_max` (number, MT5 `SYMBOL_VOLUME_MAX`): - `volume_step` (number, MT5 `SYMBOL_VOLUME_STEP`): - `stops_level` (integer, MT5 `SYMBOL_TRADE_STOPS_LEVEL`): The closest stops may be to the price, in points. - `freeze_level` (integer, MT5 `SYMBOL_TRADE_FREEZE_LEVEL`): How close to the price an order or stop is frozen, in points. - `filling_mode` (integer, MT5 `SYMBOL_FILLING_MODE`): MT5's flags, as `filling_modes` spells them out. - `trade_mode` (integer, MT5 `SYMBOL_TRADE_MODE`): MT5's value, as `trading` spells it out. - `execution_mode` (integer, MT5 `SYMBOL_TRADE_EXEMODE`): MT5's value, as `execution` spells it out. - `order_mode` (integer, MT5 `SYMBOL_ORDER_MODE`): MT5's flags, as `order_types` spells them out. - `expiration_mode` (integer, MT5 `SYMBOL_EXPIRATION_MODE`): MT5's flags, as `expirations` spells them out. - `currency_base` (string, MT5 `SYMBOL_CURRENCY_BASE`): - `currency_profit` (string, MT5 `SYMBOL_CURRENCY_PROFIT`): - `currency_margin` (string, MT5 `SYMBOL_CURRENCY_MARGIN`): - `filling_modes` (enum[]): The `type_filling` modes MT5's `SYMBOL_FILLING_MODE` flags allow. `return` has no flag: whether it is accepted depends on the symbol's execution and the broker. - `execution` (enum, or null): MT5's `SYMBOL_TRADE_EXEMODE`. Instant and request execution need `price` (and use `deviation`). One of: `request`, `instant`, `market`, `exchange`. - `order_types` (enum[]): The orders the symbol allows (MT5's `SYMBOL_ORDER_MODE`). - `expirations` (enum[]): The `type_time` values the symbol allows (MT5's `SYMBOL_EXPIRATION_MODE`). - `trading` (enum, or null): MT5's `SYMBOL_TRADE_MODE`: whether and which way the symbol can be traded. One of: `disabled`, `long_only`, `short_only`, `close_only`, `full`. ### Answers - 200: The symbol. - 401: - `missing_api_key`: No API key: send it as `Authorization: Bearer `.; `invalid_api_key`: The key is not a workspace's current key (a rolled key stops working within about a minute). - 404: - `no_such_account`: No such account, or one the key's workspace doesn't have: the two look the same.; `no_such_symbol`: The broker has no symbol by that name. - 503: - `account_not_connected`: The account's terminal is not connected to the engine (stopped, starting, or restarting). Nothing was sent, except by the kill switch: engaging it still engages it, and may already have deleted pending orders.; `terminal_error`: The terminal did not give the answer asked for.; `engine_busy`: The account's engine host has too many calls in flight (256). Nothing was done; try again.; `engine_unavailable`: The account's engine host is not connected to Pipsocket, or disconnected while the call waited. A trade it already had is still settled: look it up. - 504: - `terminal_timeout`: The account's terminal did not answer within 5 seconds.; `engine_timeout`: The account's engine did not answer within 30 seconds. ### Example ```bash curl "https://api.pipsocket.com/v1/accounts/acc_01m6tx3k9f2qw8r7bznd5yvh4c/symbols/EURUSD" \ -H "Authorization: Bearer $PIPSOCKET_KEY" ``` 200 symbol: ```json { "available": true, "contract_size": 100000, "currency_base": "EUR", "currency_margin": "EUR", "currency_profit": "USD", "description": "Euro vs US Dollar", "digits": 5, "execution": "market", "execution_mode": 2, "expiration_mode": 15, "expirations": [ "gtc", "day", "specified", "specified_day" ], "filling_mode": 2, "filling_modes": [ "ioc" ], "freeze_level": 0, "name": "EURUSD", "order_mode": 127, "order_types": [ "market", "limit", "stop", "stop_limit", "sl", "tp", "close_by" ], "point": 0.00001, "stops_level": 0, "tick_size": 0.00001, "tick_value": 1, "trade_mode": 4, "trading": "full", "volume_max": 500, "volume_min": 0.01, "volume_step": 0.01 } ``` ## Get a symbol's price `GET /v1/accounts/{account}/symbols/{symbol}/tick` The symbol's latest tick (MT5's `MqlTick`) from the terminal. A symbol the terminal has just added to Market Watch can take up to 2 seconds to have a price. ### Path - `account` (string, required): The account's id, `acc_` and 26 characters, as the dashboard shows it. - `symbol` (string, required): The symbol exactly as the broker names it, such as `EURUSD`. ### Response - `symbol` (string): - `bid` (number, MT5 `bid`): - `ask` (number, MT5 `ask`): - `time_msc` (integer, or null, MT5 `time_msc`): Broker server time, milliseconds since 1970. - `last` (number, or null, MT5 `last`): - `volume` (number, or null, MT5 `volume_real`): - `flags` (integer, or null, MT5 `flags`): MT5's `TICK_FLAG_*` bits: what changed. ### Answers - 200: The latest tick. - 401: - `missing_api_key`: No API key: send it as `Authorization: Bearer `.; `invalid_api_key`: The key is not a workspace's current key (a rolled key stops working within about a minute). - 404: - `no_such_account`: No such account, or one the key's workspace doesn't have: the two look the same.; `no_such_symbol`: The broker has no symbol by that name. - 503: - `account_not_connected`: The account's terminal is not connected to the engine (stopped, starting, or restarting). Nothing was sent, except by the kill switch: engaging it still engages it, and may already have deleted pending orders.; `terminal_error`: The terminal did not give the answer asked for.; `no_price`: The terminal has no price for the symbol yet (it waited 2 seconds).; `engine_busy`: The account's engine host has too many calls in flight (256). Nothing was done; try again.; `engine_unavailable`: The account's engine host is not connected to Pipsocket, or disconnected while the call waited. A trade it already had is still settled: look it up. - 504: - `terminal_timeout`: The account's terminal did not answer within 5 seconds.; `engine_timeout`: The account's engine did not answer within 30 seconds. ### Example ```bash curl "https://api.pipsocket.com/v1/accounts/acc_01m6tx3k9f2qw8r7bznd5yvh4c/symbols/EURUSD/tick" \ -H "Authorization: Bearer $PIPSOCKET_KEY" ``` 200 tick: ```json { "ask": 1.08412, "bid": 1.0841, "flags": 6, "last": 0, "symbol": "EURUSD", "time_msc": 1794067825114, "volume": 0 } ``` --- # Kill switch Source: https://docs.pipsocket.com/api/kill-switch Block new exposure and flatten the account. All calls: `https://api.pipsocket.com`, with `Authorization: Bearer `. ## Get the kill switch `GET /v1/accounts/{account}/kill-switch` Whether the account's kill switch is engaged. ### Path - `account` (string, required): The account's id, `acc_` and 26 characters, as the dashboard shows it. ### Response - `engaged` (boolean): - `since` (integer, or null): When it was engaged: seconds since 1970 (UTC). Null when it is not engaged. - `deviation` (integer, or null): The deviation, in points, its closing deals carry. Null when it is not engaged. ### Answers - 200: The kill switch. - 401: - `missing_api_key`: No API key: send it as `Authorization: Bearer `.; `invalid_api_key`: The key is not a workspace's current key (a rolled key stops working within about a minute). - 404: - `no_such_account`: No such account, or one the key's workspace doesn't have: the two look the same. - 503: - `engine_busy`: The account's engine host has too many calls in flight (256). Nothing was done; try again.; `engine_unavailable`: The account's engine host is not connected to Pipsocket, or disconnected while the call waited. A trade it already had is still settled: look it up. - 504: - `engine_timeout`: The account's engine did not answer within 30 seconds. ### Example ```bash curl "https://api.pipsocket.com/v1/accounts/acc_01m6tx3k9f2qw8r7bznd5yvh4c/kill-switch" \ -H "Authorization: Bearer $PIPSOCKET_KEY" ``` 200 engaged: ```json { "deviation": 20, "engaged": true, "since": 1794064225 } ``` 200 lifted: ```json { "deviation": null, "engaged": false, "since": null } ``` ## Engage the kill switch `POST /v1/accounts/{account}/kill-switch` Blocks new exposure first (new orders and changes to pending orders are refused with 423 until it is lifted; the block survives restarts), then deletes every pending order and closes every position, each as one request sent once. It first waits up to 6 seconds for trades still being sent. Engaging it again retries whatever is left. Closing, close by, cancelling and setting stops still work while it is engaged. ### Path - `account` (string, required): The account's id, `acc_` and 26 characters, as the dashboard shows it. ### Body Engaging the kill switch may carry the deviation (in points) for its closing deals, which brokers with instant or request execution need; MT5's empty value, 0, otherwise. - `deviation` (integer, optional, MT5 `deviation`): The largest difference from the current price the closing deals accept, in points, for instant or request execution. 0 if left out. ### Response - `flat` (boolean): No positions or pending orders in a fresh read of the account, and no trade that could add exposure without a known outcome (`unknown` included). - `cancelled` (object[]): Each pending order and the removal sent for it (or the one already waiting for its answer). - `closed` (object[]): Each position and the close sent for it (or the one already waiting for its answer). - `remaining` (object, or null): What a fresh read found afterwards; null if the terminal did not answer it. - `positions` (integer): - `orders` (integer): - `unanswered` (string[]): Ids of requests sent before the switch engaged that could add exposure and have no known outcome. If one fills and the terminal reports it, the switch closes what it opened. - `kill_switch` (object): Whether the account's kill switch is engaged. - `engaged` (boolean): - `since` (integer, or null): When it was engaged: seconds since 1970 (UTC). Null when it is not engaged. - `deviation` (integer, or null): The deviation, in points, its closing deals carry. Null when it is not engaged. - `message` (string): What the outcome means, in a sentence. ### Answers - 200: The switch is engaged; each request it sent, with MT5's answer, and whether the account is now flat. - 401: - `missing_api_key`: No API key: send it as `Authorization: Bearer `.; `invalid_api_key`: The key is not a workspace's current key (a rolled key stops working within about a minute). - 404: - `no_such_account`: No such account, or one the key's workspace doesn't have: the two look the same. - 422: - `invalid_request`: A field, query parameter or header is missing, malformed or not allowed, or the body is not JSON. Nothing was sent. - 503: - `account_not_connected`, with `kill_switch`: the switch is engaged (and stays engaged), but the terminal stopped answering: no position was closed, though pending orders may already have been deleted. Engage it again once the terminal is connected; a sweep also runs when it reconnects.; `engine_busy`: The account's engine host has too many calls in flight (256). Nothing was done; try again.; `engine_unavailable`: The account's engine host is not connected to Pipsocket, or disconnected while the call waited. A trade it already had is still settled: look it up. - 504: - `engine_timeout`: The account's engine did not answer within 30 seconds. ### Example ```bash curl -X POST "https://api.pipsocket.com/v1/accounts/acc_01m6tx3k9f2qw8r7bznd5yvh4c/kill-switch" \ -H "Authorization: Bearer $PIPSOCKET_KEY" \ -H "Content-Type: application/json" \ -d '{ "deviation": 20 }' ``` 200 flat: ```json { "cancelled": [], "closed": [ { "position": 881402311, "request": { "message": "The request was completed.", "request": "req_9b1e4d7c2a5f8e0b3d6a9c12", "result": { "ask": 1.08412, "bid": 1.0841, "comment": "Request executed", "deal": 771203498, "order": 881402390, "position": 0, "price": 1.0841, "retcode": 10009, "retcode_external": 0, "retcode_name": "TRADE_RETCODE_DONE", "volume": 0.1 }, "sent": { "action": "deal", "comment": "kill switch", "deviation": 20, "expiration": 0, "magic": 0, "order": 0, "position": 881402311, "position_by": 0, "price": 1.0841, "sl": 0, "stoplimit": 0, "symbol": "EURUSD", "tp": 0, "type": "sell", "type_filling": "ioc", "type_time": "gtc", "volume": 0.1 }, "state": "done" } } ], "flat": true, "kill_switch": { "deviation": 20, "engaged": true, "since": 1794064225 }, "message": "The kill switch is engaged and the account has no positions or pending orders.", "remaining": { "orders": 0, "positions": 0 }, "unanswered": [] } ``` ## Lift the kill switch `DELETE /v1/accounts/{account}/kill-switch` Lifts the account's kill switch: new orders and changes to pending orders are accepted again. Lifting a switch that is not engaged changes nothing. ### Path - `account` (string, required): The account's id, `acc_` and 26 characters, as the dashboard shows it. ### Response - `engaged` (boolean): - `since` (integer, or null): When it was engaged: seconds since 1970 (UTC). Null when it is not engaged. - `deviation` (integer, or null): The deviation, in points, its closing deals carry. Null when it is not engaged. ### Answers - 200: The kill switch, lifted. - 401: - `missing_api_key`: No API key: send it as `Authorization: Bearer `.; `invalid_api_key`: The key is not a workspace's current key (a rolled key stops working within about a minute). - 404: - `no_such_account`: No such account, or one the key's workspace doesn't have: the two look the same. - 422: - `invalid_request`: A field, query parameter or header is missing, malformed or not allowed, or the body is not JSON. Nothing was sent. - 503: - `engine_busy`: The account's engine host has too many calls in flight (256). Nothing was done; try again.; `engine_unavailable`: The account's engine host is not connected to Pipsocket, or disconnected while the call waited. A trade it already had is still settled: look it up. - 504: - `engine_timeout`: The account's engine did not answer within 30 seconds. ### Example ```bash curl -X DELETE "https://api.pipsocket.com/v1/accounts/acc_01m6tx3k9f2qw8r7bznd5yvh4c/kill-switch" \ -H "Authorization: Bearer $PIPSOCKET_KEY" ``` 200 lifted: ```json { "deviation": null, "engaged": false, "since": null } ``` --- # The WebSocket stream Source: https://docs.pipsocket.com/websocket Fills, deals, prices and the account as they happen, and calls over the same socket. Each account has a stream: a WebSocket that pushes what happens on the account as it happens, and takes the API's calls as messages. ```text wss://wss.pipsocket.com/v1/accounts/{account}/stream Authorization: Bearer $PIPSOCKET_KEY ``` The key goes in the `Authorization` header of the upgrade request, as on REST, so connect from your server (browsers can't set that header). It is checked when the stream connects, not on each call: see [rolling the key](/authentication#rolling-the-key). Before the upgrade, a missing or wrong key answers `401` and an account your workspace doesn't have `404`, as on REST; a request that isn't a WebSocket upgrade answers `426 upgrade_required`. ```js // npm install ws import WebSocket from "ws" const socket = new WebSocket("wss://wss.pipsocket.com/v1/accounts/acc_01m6tx3k9f2qw8r7bznd5yvh4c/stream", { headers: { Authorization: `Bearer ${process.env.PIPSOCKET_KEY}` }, }) socket.on("open", () => { socket.send(JSON.stringify({ id: "t1", method: "PUT", path: "/ticks", body: { symbols: ["EURUSD"] } })) }) socket.on("message", (data) => console.log(JSON.parse(data.toString()))) ``` ```python # pip install websockets import asyncio, json, os import websockets async def main(): url = "wss://wss.pipsocket.com/v1/accounts/acc_01m6tx3k9f2qw8r7bznd5yvh4c/stream" headers = {"Authorization": f"Bearer {os.environ['PIPSOCKET_KEY']}"} async with websockets.connect(url, additional_headers=headers) as socket: await socket.send(json.dumps({"id": "t1", "method": "PUT", "path": "/ticks", "body": {"symbols": ["EURUSD"]}})) async for message in socket: print(json.loads(message)) asyncio.run(main()) ``` The first message is `{ "type": "subscribed", "account": "acc_..." }`. Every message is a JSON object with a `type`. ## Events | `type` | When | Fields | | --- | --- | --- | | `request` | A trade request settled (filled, rejected, refused), however it was sent: REST, this stream, or the kill switch. | As [`GET /requests/{request}`](/api/look-up-a-request) shows it: `request`, `state`, `sent`, `result`, `message`. | | `deal` | A deal on the account: a fill, a close, a stop loss or take profit, a balance operation. | `deal`, as in [deal history](/api/history). | | `transaction` | MT5's trade transaction (`OnTradeTransaction`): orders and positions changing. | `transaction` (MT5's type, such as `deal_add` or `position`), `order`, `deal`, `position`, `position_by`, `symbol`, `order_type`, `order_state`, `deal_type`, `volume`, `price`, `sl`, `tp`. | | `account` | Every second. | `connected`, `trade_allowed`, `balance`, `equity`, `credit`, `margin`, `margin_free`, `positions`, `orders`, `server_time`. | | `status` | The account's status changed, the terminal connecting and disconnecting included. | `status`, `detail` (see [Accounts and ids](/accounts#accounts)). | | `tick` | A price change of a symbol you asked for (see Ticks). | `symbol`, `time_msc`, `bid`, `ask`, `last`, `volume`, `flags` (MT5's `MqlTick`). | | `lagged` | The stream fell behind and dropped events. | `missed`: how many. Read the state over REST. | | `engine_disconnected` | The account's host lost its connection to Pipsocket. | None. See Disconnections. | Your own fill arrives as a `request` event whichever way you sent the order, so a client can send over REST and listen here. ## Calls Send any API call as a message, with `path` as under `/v1/accounts/{account}`: ```json { "id": "o1", "method": "POST", "path": "/orders", "body": { "symbol": "EURUSD", "type": "buy", "volume": 0.01, "type_filling": "ioc" }, "idempotency_key": "rebalance-0412" } ``` - `id` is your own string, and comes back on the answer: `{ "type": "response", "id": "o1", "status": 200, "body": {...} }`. `status` and `body` are exactly what the REST call answers. - `idempotency_key` is the `Idempotency-Key` header. `path` may carry a query: `/history/deals?from=1794019000&to=1794021000`. The account itself is `/`. - A call runs through the same checks, kill switch and idempotency as REST. Calls run side by side, so a slow one doesn't hold up the next. - At most 16 calls can wait for their answer on one stream. Another is refused: `{ "type": "error", "id": "o2", "error": "too_many_calls", "message": "..." }`. - A message that isn't a call (no string `id`, `method` or `path`) is refused with `invalid_message`, and a call while the host is away with `engine_unavailable`. The stream stays open. ## Ticks Ask for prices with a call to `/ticks`, kept by the stream itself: ```json { "id": "t1", "method": "PUT", "path": "/ticks", "body": { "symbols": ["EURUSD", "XAUUSD"] } } ``` - Send all the symbols you want each time, up to 100; `[]` stops. The answer is the stream's symbols: `{ "type": "response", "id": "t1", "status": 200, "body": { "symbols": ["EURUSD", "XAUUSD"] } }`. `GET /ticks` reads them back. - A `tick` event follows for each symbol's current price, then one for each price change as the broker sent it. Of changes closer together than 10 ms, only the latest is sent. - An account's streams share the 100 symbols between them: a set that would pass that is `422 too_many_symbols`. A list that isn't up to 100 symbol names is `422 invalid_request`, and a method other than `GET` or `PUT` is `405 method_not_allowed`. ## Keeping it open Send the text message `ping` and the stream answers `pong`, without a call: use it to keep idle connections (and proxies between you) from timing out. ## Disconnections - **The host goes away.** You get `engine_disconnected`, and calls still waiting get no answer. A trade among them may or may not have reached the host. Send it again with the same `idempotency_key` once the host is back: you get the first request if the host recorded it (it settles all the same), and the trade is sent if it never arrived. A trade sent without a key can't be retried safely: check positions and history first. Your stream stays open; events and ticks resume when the host reconnects. - **Your socket closes.** Connect again and send your `/ticks` set again: it belonged to the closed stream. Events that happened meanwhile aren't sent again, so read what you need over REST: [positions](/api/positions), [pending orders](/api/pending-orders), [history](/api/history), and [requests](/api/look-up-a-request) you were waiting for. - **`lagged`.** The stream dropped events: read the state over REST, as above. --- # Errors and retcodes Source: https://docs.pipsocket.com/errors The API's refusals, MT5's retcodes, and what to do about each. Two kinds of answers say something went wrong, and they mean different things: - **A refusal** is an HTTP error with `{ "error": "", "message": "..." }`. Check `error`, not `message` (its wording may change). Almost every refusal means nothing was done. Two mean the call may have reached the account's host before the answer was lost: `503 engine_unavailable` (the host disconnected while the call waited) and `504 engine_timeout`. After those, a trade's outcome is unknown: retry it with the **same** `Idempotency-Key`, which returns the first request if the host recorded it, and sends it if not. - **The kill switch** is the exception. Engaging it while the terminal is away answers `503 account_not_connected` with `kill_switch`: the switch is engaged all the same (it blocks new exposure, and survives restarts), and pending orders may already have been deleted if the terminal stopped answering part way. Read [the kill switch](/api/kill-switch), positions and pending orders, and engage it again: engaging again retries whatever is left (it takes no `Idempotency-Key`). - **MT5's answer** to a trade is `200` with `"state": "done"`, whether MT5 filled the order or rejected it. Read `result.retcode`: `10009` is done; `10008` is placed (a pending order); the rest are partial fills or rejections. A rejection can come from the trade server, or from the terminal refusing to send the request at all (then `result.comment` is the terminal's), so `done` doesn't prove the broker saw it. ```json { "request": "req_5f0c2a9e41d7b3a8c6e2f190", "state": "done", "result": { "retcode": 10016, "retcode_name": "TRADE_RETCODE_INVALID_STOPS", "comment": "Invalid stops", "...": "..." }, "message": "The stop loss or take profit is invalid for this symbol or too close to the price.", "sent": { "...": "..." } } ``` ## What to do | Answer | Do | | --- | --- | | `200` with `"state": "done"` | Read `result.retcode`. A rejection is final: nothing more happens to that request. Change it before sending it again (with a new `Idempotency-Key`). | | `202` with `"state": "pending"` | Don't send it again. [Look it up](/api/look-up-a-request), or wait for its `request` event on the [stream](/websocket). | | `401` | Check the key: see [Authentication](/authentication). | | `403` with `error code: 1010` | Cloudflare refused your client's `User-Agent` before the API saw the call (Python's `urllib` sends one it refuses). Set your own `User-Agent`, or use a client such as `requests`. | | `404` | Check the account id, ticket or symbol. Closing, modifying and setting stops read the position or order fresh first: one that's gone is `404`. | | `422` | Fix the field `message` names. Nothing was sent. | | `423 kill_switch_engaged` | The account's [kill switch](/api/kill-switch) is engaged: lift it to open new exposure. | | `503`, `504` | Retry a trade call with the **same** `Idempotency-Key`, never a new one: if the first call was recorded you get it back, and nothing is sent twice. Most are refused before anything is sent, but after `engine_unavailable` or `engine_timeout` the first call may have been sent. A trade sent without a key can't be retried safely: check [positions](/api/positions) and [history](/api/history) first. | ## Error codes Every code the API answers with. "From" says who refuses: the API, before the account's host is reached, or the engine on the host. | Status | Code | From | Meaning | | --- | --- | --- | --- | | 401 | `missing_api_key` | API | No API key: send it as `Authorization: Bearer `. | | 401 | `invalid_api_key` | API | The key is not a workspace's current key (a rolled key stops working within about a minute). | | 404 | `no_such_account` | Engine | No such account, or one the key's workspace doesn't have: the two look the same. | | 404 | `no_such_order` | Engine | The account has no pending order with that ticket (read fresh from the terminal). | | 404 | `no_such_position` | Engine | The account has no open position with that ticket (read fresh from the terminal). | | 404 | `no_such_request` | Engine | The account has no request with that id (requests are kept 7 days). | | 404 | `no_such_symbol` | Engine | The broker has no symbol by that name. | | 422 | `invalid_request` | Engine | A field, query parameter or header is missing, malformed or not allowed, or the body is not JSON. Nothing was sent. | | 422 | `range_too_large` | Engine | The history range holds more than one answer can carry: ask for a shorter range. | | 423 | `kill_switch_engaged` | Engine | The account's kill switch is engaged: new orders and changes to pending orders are refused until it is lifted. Nothing was sent. | | 503 | `account_not_connected` | Engine | The account's terminal is not connected to the engine (stopped, starting, or restarting). Nothing was sent, except by the kill switch: engaging it still engages it, and may already have deleted pending orders. | | 503 | `bridge_outdated` | Engine | The account's terminal runs an older bridge that can't trade: restart the account to update it. Nothing was sent. | | 503 | `account_restarting` | Engine | The account's terminal is being replaced. Nothing was sent; try again in a minute. | | 503 | `bad_command` | Engine | The terminal refused the command, for example a negative `expiration`, or a history range MT5 can't select. | | 503 | `terminal_error` | Engine | The terminal did not give the answer asked for. | | 503 | `symbol_too_large` | Engine | One symbol's entry is too large for the terminal to list. | | 503 | `no_price` | Engine | The terminal has no price for the symbol yet (it waited 2 seconds). | | 503 | `engine_busy` | Engine | The account's engine host has too many calls in flight (256). Nothing was done; try again. | | 503 | `engine_unavailable` | API | The account's engine host is not connected to Pipsocket, or disconnected while the call waited. A trade it already had is still settled: look it up. | | 504 | `terminal_timeout` | Engine | The account's terminal did not answer within 5 seconds. | | 504 | `engine_timeout` | API | The account's engine did not answer within 30 seconds. | A trade call's `503` can also be a stored request the terminal didn't send (`"state": "refused"`, with `result.error` saying why, such as `busy` when 1,000 trades are already waiting for the trade server). A ticket in the path that isn't a whole number answers `400` with no body. ## MT5 retcodes MT5's trade server return codes (`MqlTradeResult.retcode`), with the names the API sends in `retcode_name`. A code MT5 doesn't document comes back as `UNKNOWN`. | Code | Name | Meaning | | --- | --- | --- | | 0 | `OK` | The request passed the check. | | 10004 | `TRADE_RETCODE_REQUOTE` | The broker requoted the price. | | 10006 | `TRADE_RETCODE_REJECT` | The trade server rejected the request. | | 10007 | `TRADE_RETCODE_CANCEL` | The request was cancelled by the trader. | | 10008 | `TRADE_RETCODE_PLACED` | The order was placed; execution is not confirmed yet. | | 10009 | `TRADE_RETCODE_DONE` | The request was completed. | | 10010 | `TRADE_RETCODE_DONE_PARTIAL` | Only part of the request was completed. | | 10011 | `TRADE_RETCODE_ERROR` | The trade server could not process the request. | | 10012 | `TRADE_RETCODE_TIMEOUT` | The request was cancelled by a timeout. | | 10013 | `TRADE_RETCODE_INVALID` | The request is invalid. | | 10014 | `TRADE_RETCODE_INVALID_VOLUME` | The volume is invalid for this symbol. | | 10015 | `TRADE_RETCODE_INVALID_PRICE` | The price is invalid. | | 10016 | `TRADE_RETCODE_INVALID_STOPS` | The stop loss or take profit is invalid for this symbol or too close to the price. | | 10017 | `TRADE_RETCODE_TRADE_DISABLED` | Trading is disabled. | | 10018 | `TRADE_RETCODE_MARKET_CLOSED` | The market is closed. | | 10019 | `TRADE_RETCODE_NO_MONEY` | There is not enough money for the request. | | 10020 | `TRADE_RETCODE_PRICE_CHANGED` | The price changed. | | 10021 | `TRADE_RETCODE_PRICE_OFF` | There are no quotes to process the request. | | 10022 | `TRADE_RETCODE_INVALID_EXPIRATION` | The order expiration is invalid. | | 10023 | `TRADE_RETCODE_ORDER_CHANGED` | The order changed state. | | 10024 | `TRADE_RETCODE_TOO_MANY_REQUESTS` | Too many requests in a short time. | | 10025 | `TRADE_RETCODE_NO_CHANGES` | The request changes nothing. | | 10026 | `TRADE_RETCODE_SERVER_DISABLES_AT` | Automated trading is disabled by the server. | | 10027 | `TRADE_RETCODE_CLIENT_DISABLES_AT` | Automated trading is disabled in the terminal. | | 10028 | `TRADE_RETCODE_LOCKED` | The request is locked for processing. | | 10029 | `TRADE_RETCODE_FROZEN` | The order or position is frozen. | | 10030 | `TRADE_RETCODE_INVALID_FILL` | The filling mode is not allowed for this symbol. | | 10031 | `TRADE_RETCODE_CONNECTION` | There is no connection to the trade server. | | 10032 | `TRADE_RETCODE_ONLY_REAL` | This is only allowed for live accounts. | | 10033 | `TRADE_RETCODE_LIMIT_ORDERS` | The account has reached its limit of pending orders. | | 10034 | `TRADE_RETCODE_LIMIT_VOLUME` | The symbol has reached its volume limit for orders and positions. | | 10035 | `TRADE_RETCODE_INVALID_ORDER` | The order type is incorrect or not allowed. | | 10036 | `TRADE_RETCODE_POSITION_CLOSED` | The position is already closed. | | 10038 | `TRADE_RETCODE_INVALID_CLOSE_VOLUME` | The close volume is more than the position's volume. | | 10039 | `TRADE_RETCODE_CLOSE_ORDER_EXIST` | A close order already exists for the position. | | 10040 | `TRADE_RETCODE_LIMIT_POSITIONS` | The account has reached its limit of open positions. | | 10041 | `TRADE_RETCODE_REJECT_CANCEL` | The pending order's activation was rejected and the order cancelled. | | 10042 | `TRADE_RETCODE_LONG_ONLY` | Only long positions are allowed for this symbol. | | 10043 | `TRADE_RETCODE_SHORT_ONLY` | Only short positions are allowed for this symbol. | | 10044 | `TRADE_RETCODE_CLOSE_ONLY` | Only closing positions is allowed for this symbol. | | 10045 | `TRADE_RETCODE_FIFO_CLOSE` | Positions may only be closed first in, first out. | | 10046 | `TRADE_RETCODE_HEDGE_PROHIBITED` | Opposite positions on one symbol are not allowed. | --- # MT5 field map Source: https://docs.pipsocket.com/mt5-field-map Which MT5 field each API field is, and what each call fills in itself. Fields keep MT5's names and meanings, with readable values in place of MT5's numbers: `"type": "buy_limit"` is `ORDER_TYPE_BUY_LIMIT`, `"type_filling": "ioc"` is `ORDER_FILLING_IOC`. ## The trade request Every trade call records one `MqlTradeRequest` and sends it once; every answer shows it as `sent`, field for field (whether it reached MT5 is the answer's `state` and `result`). Fields a call doesn't use carry MT5's empty values: `0`, `""`, `fok` for `type_filling` and `gtc` for `type_time`. | API field | MT5 field | Meaning | | --- | --- | --- | | `action` | `action` | What the request does. | | `symbol` | `symbol` | The symbol, exactly as the broker names it. | | `type` | `type` | The order type. | | `volume` | `volume` | Lots. | | `price` | `price` | The price: a pending order's, or the one instant and request execution trade at. | | `stoplimit` | `stoplimit` | A stop-limit order's limit price, placed once `price` is reached. | | `sl` | `sl` | Stop loss price; 0 for none. | | `tp` | `tp` | Take profit price; 0 for none. | | `deviation` | `deviation` | The largest difference from `price` MT5 accepts, in points. | | `type_filling` | `type_filling` | How the order may fill. | | `type_time` | `type_time` | How long a pending order lasts. | | `expiration` | `expiration` | Broker server time, seconds since 1970, as MT5 takes it. | | `order` | `order` | The pending order the request is about (modify, remove). | | `position` | `position` | The position the request is about (close, stops, close by). | | `position_by` | `position_by` | The opposite position, for close by. | | `magic` | `magic` | Your own number, kept by MT5 on the order, its deals and its position. | | `comment` | `comment` | Up to 31 characters, kept by MT5 on the order. | What each call fills in, beyond the fields you send: | Call | `action` | Also filled in | | --- | --- | --- | | [Place an order](/api/place-an-order) | `deal` for `buy` and `sell`, else `pending` | Nothing else. | | [Modify an order](/api/modify-an-order) | `modify` | `order` from the path, and `symbol` from the pending order. | | [Cancel an order](/api/cancel-an-order) | `remove` | `order` from the path. | | [Set stops](/api/set-stops) | `sltp` | `position` from the path, and `symbol` from the position. | | [Close a position](/api/close-a-position) | `deal` | `position` from the path; `symbol` from the position; `type` the other way (`sell` closes a buy). | | [Close by](/api/close-by) | `close_by` | `position` from the path, `type: close_by`, and `symbol` from the position. | | [Kill switch](/api/kill-switch) | `remove` for each pending order, `deal` for each position | For a close: the position's whole `volume`, the current bid or ask as `price`, the first filling mode the symbol allows (`fok`, else `ioc`, else `return`), your `deviation`, and the comment `kill switch`. | Nothing else is set for you: no `price` for a market order, no filling mode, no rounding. A [dry run](/api/check-an-order) sends the same request to MT5's `OrderCheck` without trading. ## Bodies you send [Place an order](/api/place-an-order) and [Check an order](/api/check-an-order): | API field | MT5 field | Meaning | | --- | --- | --- | | `symbol` | `symbol` | The symbol exactly as the broker names it, such as `EURUSD`. | | `type` | `type` | What to send. | | `volume` | `volume` | Lots. | | `type_filling` | `type_filling` | How the order may fill. | | `price` | `price` | Required for pending orders: the price the order waits for. | | `stoplimit` | `stoplimit` | Required for `buy_stop_limit` and `sell_stop_limit`: the price of the limit order placed once `price` is reached. | | `sl` | `sl` | Stop loss price, set in the same request. | | `tp` | `tp` | Take profit price, set in the same request. | | `deviation` | `deviation` | The largest difference from `price` MT5 accepts, in points, for instant or request execution. | | `type_time` | `type_time` | How long a pending order lasts. | | `expiration` | `expiration` | When a pending order expires: broker server time, seconds since 1970. | | `magic` | `magic` | Your own number for the order, kept by MT5 on the order, its deals and its position. | | `comment` | `comment` | Up to 31 characters, kept by MT5 on the order. | [Modify an order](/api/modify-an-order): | API field | MT5 field | Meaning | | --- | --- | --- | | `price` | `price` | The price the order waits for. | | `sl` | `sl` | Stop loss price; 0 removes it. | | `tp` | `tp` | Take profit price; 0 removes it. | | `type_time` | `type_time` | How long the order lasts. | | `stoplimit` | `stoplimit` | Required when the order is a stop-limit order: the price of the limit order placed once `price` is reached. | | `expiration` | `expiration` | When the order expires: broker server time, seconds since 1970. | [Close a position](/api/close-a-position): | API field | MT5 field | Meaning | | --- | --- | --- | | `volume` | `volume` | Lots to close: the position's whole volume, or part of it. | | `type_filling` | `type_filling` | How the closing deal may fill. | | `price` | `price` | Sent as given (0 if left out): brokers with instant or request execution need it, those with market or exchange execution ignore it. | | `deviation` | `deviation` | The largest difference from `price` MT5 accepts, in points, for instant or request execution. | | `magic` | `magic` | Your own number, kept by MT5 on the closing deal. | | `comment` | `comment` | Up to 31 characters, kept by MT5 on the closing deal. | [Set stops](/api/set-stops) (`PositionLevels`) and [Close by](/api/close-by) (`CloseBy`): | API field | MT5 field | Meaning | | --- | --- | --- | | `sl` | `sl` | Stop loss price; 0 removes it. | | `tp` | `tp` | Take profit price; 0 removes it. | | API field | MT5 field | Meaning | | --- | --- | --- | | `position_by` | `position_by` | The opposite position's ticket. | ## MT5's answer A trade's `result` is MT5's `MqlTradeResult`: | API field | MT5 field | Meaning | | --- | --- | --- | | `retcode` | `retcode` | MT5's return code: see Errors and retcodes. | | `retcode_name` | Pipsocket | The return code's name; `UNKNOWN` for a code MT5 doesn't document. | | `comment` | `comment` | The broker's comment on the answer. | | `order` | `order` | The order's ticket, if one was placed. | | `deal` | `deal` | The deal's ticket, if one was made. | | `position` | Pipsocket | The position's ticket, where the trade server gives it. | | `volume` | `volume` | The volume dealt. | | `price` | `price` | The price dealt. | | `bid` | `bid` | The bid when the request was handled (requotes). | | `ask` | `ask` | The ask when the request was handled (requotes). | | `retcode_external` | `retcode_external` | The external trading system's code, if the broker routes to one. | A dry run's `result` is MT5's `MqlTradeCheckResult`: | API field | MT5 field | Meaning | | --- | --- | --- | | `passed` | Pipsocket | Whether `OrderCheck` passed the request. | | `retcode` | `retcode` | MT5's return code: 0 when the check passed. | | `retcode_name` | Pipsocket | The return code's name; `UNKNOWN` for a code MT5 doesn't document. | | `comment` | `comment` | | | `balance` | `balance` | The balance after the trade. | | `equity` | `equity` | The equity after the trade. | | `profit` | `profit` | The floating profit after the trade. | | `margin` | `margin` | The margin the trade takes. | | `margin_free` | `margin_free` | The free margin after the trade. | | `margin_level` | `margin_level` | The margin level after the trade, in percent. | ## The account's state [Positions](/api/positions) (`POSITION_*`): | API field | MT5 field | Meaning | | --- | --- | --- | | `ticket` | `POSITION_TICKET` | The position's ticket: use it to close the position or set its stops. | | `identifier` | `POSITION_IDENTIFIER` | The position's id, which stays the same if the broker changes the ticket. | | `symbol` | `POSITION_SYMBOL` | | | `type` | Pipsocket | `buy` or `sell` (MT5's `POSITION_TYPE`). | | `volume` | `POSITION_VOLUME` | | | `price_open` | `POSITION_PRICE_OPEN` | | | `sl` | `POSITION_SL` | | | `tp` | `POSITION_TP` | | | `magic` | `POSITION_MAGIC` | | | `comment` | `POSITION_COMMENT` | | | `time_msc` | `POSITION_TIME_MSC` | When it was opened: broker server time, milliseconds since 1970. | [Pending orders](/api/pending-orders) (`ORDER_*`): | API field | MT5 field | Meaning | | --- | --- | --- | | `ticket` | `ORDER_TICKET` | | | `symbol` | `ORDER_SYMBOL` | | | `type` | `ORDER_TYPE` | MT5's `ENUM_ORDER_TYPE`: `buy` and `sell` are market orders (`ORDER_TYPE_BUY`, `ORDER_TYPE_SELL`); `buy_limit`, `sell_limit`, `buy_stop`, `sell_stop`, `buy_stop_limit` and `sell_stop_limit` are pending orders (`ORDER_TYPE_BUY_LIMIT` and so on); `close_by` is `ORDER_TYPE_CLOSE_BY`. | | `volume_initial` | `ORDER_VOLUME_INITIAL` | | | `volume_current` | `ORDER_VOLUME_CURRENT` | | | `price_open` | `ORDER_PRICE_OPEN` | | | `sl` | `ORDER_SL` | | | `tp` | `ORDER_TP` | | | `magic` | `ORDER_MAGIC` | | | `comment` | `ORDER_COMMENT` | | | `position` | `ORDER_POSITION_ID` | The position the order belongs to, if any. | [Deals](/api/history) (`DEAL_*`), in history and on the stream: | API field | MT5 field | Meaning | | --- | --- | --- | | `ticket` | `DEAL_TICKET` | | | `order` | `DEAL_ORDER` | The order that made the deal. | | `position` | `DEAL_POSITION_ID` | The position's id (`identifier`). | | `symbol` | `DEAL_SYMBOL` | | | `type` | Pipsocket | MT5's `DEAL_TYPE`: `buy`, `sell`, or a balance operation. | | `entry` | Pipsocket | MT5's `DEAL_ENTRY`: `in` opens or adds, `out` closes, `inout` reverses, `out_by` closes by an opposite position. | | `reason` | Pipsocket | MT5's `DEAL_REASON`: who or what made the deal (`expert` for the API, `sl`, `tp`, `so` for a stop out). | | `volume` | `DEAL_VOLUME` | | | `price` | `DEAL_PRICE` | | | `profit` | `DEAL_PROFIT` | | | `commission` | `DEAL_COMMISSION` | | | `swap` | `DEAL_SWAP` | | | `fee` | `DEAL_FEE` | | | `magic` | `DEAL_MAGIC` | | | `comment` | `DEAL_COMMENT` | | | `time_msc` | `DEAL_TIME_MSC` | Broker server time, milliseconds since 1970. | [Past orders](/api/history): | API field | MT5 field | Meaning | | --- | --- | --- | | `ticket` | `ORDER_TICKET` | | | `symbol` | `ORDER_SYMBOL` | | | `type` | `ORDER_TYPE` | MT5's `ENUM_ORDER_TYPE`: `buy` and `sell` are market orders (`ORDER_TYPE_BUY`, `ORDER_TYPE_SELL`); `buy_limit`, `sell_limit`, `buy_stop`, `sell_stop`, `buy_stop_limit` and `sell_stop_limit` are pending orders (`ORDER_TYPE_BUY_LIMIT` and so on); `close_by` is `ORDER_TYPE_CLOSE_BY`. | | `state` | Pipsocket | MT5's `ORDER_STATE`. | | `volume_initial` | `ORDER_VOLUME_INITIAL` | | | `volume_current` | `ORDER_VOLUME_CURRENT` | | | `price_open` | `ORDER_PRICE_OPEN` | | | `magic` | `ORDER_MAGIC` | | | `comment` | `ORDER_COMMENT` | | | `position` | `ORDER_POSITION_ID` | | | `time_setup_msc` | `ORDER_TIME_SETUP_MSC` | Broker server time, milliseconds since 1970. | | `time_done_msc` | `ORDER_TIME_DONE_MSC` | Broker server time, milliseconds since 1970. | A [symbol](/api/symbols) (`SYMBOL_*`): | API field | MT5 field | Meaning | | --- | --- | --- | | `name` | `SYMBOL_NAME` | | | `available` | Pipsocket | Whether the terminal could read its properties; when false the rest are empty values. | | `description` | `SYMBOL_DESCRIPTION` | | | `digits` | `SYMBOL_DIGITS` | | | `point` | `SYMBOL_POINT` | | | `tick_size` | `SYMBOL_TRADE_TICK_SIZE` | | | `tick_value` | `SYMBOL_TRADE_TICK_VALUE` | | | `contract_size` | `SYMBOL_TRADE_CONTRACT_SIZE` | | | `volume_min` | `SYMBOL_VOLUME_MIN` | | | `volume_max` | `SYMBOL_VOLUME_MAX` | | | `volume_step` | `SYMBOL_VOLUME_STEP` | | | `stops_level` | `SYMBOL_TRADE_STOPS_LEVEL` | The closest stops may be to the price, in points. | | `freeze_level` | `SYMBOL_TRADE_FREEZE_LEVEL` | How close to the price an order or stop is frozen, in points. | | `filling_mode` | `SYMBOL_FILLING_MODE` | MT5's flags, as `filling_modes` spells them out. | | `trade_mode` | `SYMBOL_TRADE_MODE` | MT5's value, as `trading` spells it out. | | `execution_mode` | `SYMBOL_TRADE_EXEMODE` | MT5's value, as `execution` spells it out. | | `order_mode` | `SYMBOL_ORDER_MODE` | MT5's flags, as `order_types` spells them out. | | `expiration_mode` | `SYMBOL_EXPIRATION_MODE` | MT5's flags, as `expirations` spells them out. | | `currency_base` | `SYMBOL_CURRENCY_BASE` | | | `currency_profit` | `SYMBOL_CURRENCY_PROFIT` | | | `currency_margin` | `SYMBOL_CURRENCY_MARGIN` | | | `filling_modes` | Pipsocket | The `type_filling` modes MT5's `SYMBOL_FILLING_MODE` flags allow. | | `execution` | Pipsocket | MT5's `SYMBOL_TRADE_EXEMODE`. | | `order_types` | Pipsocket | The orders the symbol allows (MT5's `SYMBOL_ORDER_MODE`). | | `expirations` | Pipsocket | The `type_time` values the symbol allows (MT5's `SYMBOL_EXPIRATION_MODE`). | | `trading` | Pipsocket | MT5's `SYMBOL_TRADE_MODE`: whether and which way the symbol can be traded. | A [tick](/api/symbols) (`MqlTick`): | API field | MT5 field | Meaning | | --- | --- | --- | | `symbol` | Pipsocket | | | `bid` | `bid` | | | `ask` | `ask` | | | `time_msc` | `time_msc` | Broker server time, milliseconds since 1970. | | `last` | `last` | | | `volume` | `volume_real` | | | `flags` | `flags` | MT5's `TICK_FLAG_*` bits: what changed. | --- # Rate limits Source: https://docs.pipsocket.com/rate-limits The limits Pipsocket enforces, and the broker's own. Pipsocket doesn't limit how many requests a key makes. What it does limit is how much can wait at once, so one slow call can't hold up the rest: | Limit | Where | When it's reached | | --- | --- | --- | | 5 seconds for the trade server's answer | Each trade call | `202` with `"state": "pending"`: the request goes on without you. | | 30 seconds for the host's answer | Each REST call | `504 engine_timeout`. | | 16 calls waiting for their answer | Each stream | `{ "type": "error", "error": "too_many_calls" }`; send more as answers arrive. | | 100 symbols with ticks | Each account, all its streams together | `422 too_many_symbols` on `PUT /ticks`. | | 256 calls at once | Each host, all its accounts together | `503 engine_busy`: try again. | | 1,000 trades waiting for the trade server | Each account's terminal | The request is `refused` with `busy`. | Your broker has limits of its own. MT5 answers them as retcodes, such as `10024` (`TRADE_RETCODE_TOO_MANY_REQUESTS`), `10033` (pending orders) and `10040` (open positions): see [retcodes](/errors#mt5-retcodes).