# Followers

> Attach accounts to a copier, set each one's rules for lot size, limits, direction, stops, symbols, symbol mapping and sessions, and read its live status.

A follower is an account that copies a copier's master, with its own rules for how it copies. Every rule has a default, so to attach an account you only need its ID. To read followers, your API key needs the `copiers:read` scope. To attach, change or remove them, it needs `copiers:write`.

## Attach a follower [#attach-a-follower]

```bash
curl https://api.algotradertools.com/v1/copiers/c7d1e5f2-3a4b-4c6d-8e9f-0a1b2c3d4e5f/followers \
  -H "Authorization: Bearer $ATT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "account_id": "9b2e7d4c-1a3f-4c8e-b5d6-7e8f9a0b1c2d",
    "lot_mode": "multiplier",
    "lot_value": 0.5,
    "max_lot": 5
  }'
```

Send the `account_id` (required), any of the [rules](#rules) below, and optionally `is_active`. It defaults to `true`, and `false` attaches the follower paused. The response is `201 Created` with the [follower](#the-follower-object).

The account must be one of yours, and it must:

| Requirement                                                        | Code of the `account_id` error |
| ------------------------------------------------------------------ | ------------------------------ |
| Exist and belong to you                                            | `does_not_exist`               |
| Not be this copier's master                                        | `self_copy`                    |
| Be connected with its master password (`can_trade: true`)          | `read_only_account`            |
| Be `connected`, not still connecting or released                   | `account_not_connected`        |
| Not be the master of any copier                                    | `account_is_master`            |
| Not already copy this master, in this copier or another one        | `already_following`            |
| Be a hedging account (all MT4; MT5 hedging, not netting)           | `netting_account`              |
| Allow automated trading: brokers can switch it off for one account | `automated_trading_off`        |

If the account doesn't meet a requirement, or a rule is invalid, the response is `400 validation_failed`. The netting and automated-trading checks ask the account's terminal. If the terminal doesn't answer, the request fails with `503 terminal_unavailable`. Try again shortly.

Retrying an attach is safe: if the first attempt went through, the second fails with `already_following`.

A new follower copies what the master opens after it was attached. Positions the master already has open are left alone, unless you set `copy_existing`.

## Rules [#rules]

| Field                  | Type                                                                     | Default      | Description                                                                                                                                 |
| ---------------------- | ------------------------------------------------------------------------ | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------- |
| `lot_mode`             | `multiplier`, `fixed`, `balance_ratio`, `equity_ratio` or `risk_percent` | `multiplier` | How lots are sized. See [Lot sizing](#lot-sizing)                                                                                           |
| `lot_value`            | number                                                                   | `1`          | The multiplier, the fixed lot size or the risk percentage, depending on `lot_mode`. Above 0 and up to 1000, or up to 100 for `risk_percent` |
| `adjust_contract_size` | boolean                                                                  | `true`       | Even out contract sizes between the two brokers                                                                                             |
| `below_minimum`        | `minimum` or `skip`                                                      | `minimum`    | When the size comes out below the broker's minimum lot: trade the minimum, or skip the trade                                                |
| `max_lot`              | number or `null`                                                         | `null`       | The largest lot size a copy can have. Above 0                                                                                               |
| `reverse`              | boolean                                                                  | `false`      | Trade the opposite direction                                                                                                                |
| `copy_stops`           | boolean                                                                  | `true`       | Copy stop loss and take profit, including later changes                                                                                     |
| `max_slippage_pips`    | number or `null`                                                         | `null`       | The slippage allowed when the copy is placed. `null` uses the broker's default. 0 or more                                                   |
| `max_delay_seconds`    | integer                                                                  | `60`         | How late a trade may still be copied, from 0 to 3600 seconds                                                                                |
| `copy_existing`        | boolean                                                                  | `false`      | Also copy the positions and pending orders the master already has when the follower is attached                                             |
| `copy_pending`         | boolean                                                                  | `false`      | Place the master's pending orders as pending orders too. See [Pending orders](#pending-orders)                                              |
| `symbol_filter`        | `all`, `include` or `exclude`                                            | `all`        | Which of the master's symbols are copied. See [Symbols](#symbols)                                                                           |
| `symbols`              | array of strings                                                         | `[]`         | The master's symbol names that `symbol_filter` includes or excludes. Up to 200, each up to 32 characters                                    |
| `sessions`             | array of sessions                                                        | `[]`         | When new trades are copied. Empty means any time. See [Trading sessions](#trading-sessions)                                                 |
| `timezone`             | string                                                                   | `broker`     | Which clock the `sessions` times use. See [Trading sessions](#trading-sessions)                                                             |
| `symbol_map`           | object                                                                   | `{}`         | Master symbol to follower symbol, for names that don't match by themselves. Up to 200 entries                                               |

## Lot sizing [#lot-sizing]

Each copy's size is worked out from the master's position when it opens:

| `lot_mode`      | Size of the copy                                                                             | Example                                                                                                                                       |
| --------------- | -------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `multiplier`    | The master's lots × `lot_value`                                                              | `0.5`: the master trades 1.00 lot, the copy is 0.50                                                                                           |
| `fixed`         | `lot_value` lots, whatever the master trades                                                 | `0.10`: every copy is 0.10 lots                                                                                                               |
| `balance_ratio` | The master's lots × (follower balance ÷ master balance) × `lot_value`                        | `1`: the master has 20,000 and trades 2.00 lots, the follower has 5,000, so the copy is 0.50                                                  |
| `equity_ratio`  | As `balance_ratio`, with equity instead of balance                                           | `1`: the master's equity is 10,318.40 and the follower's 5,031.20, so 1.00 lot becomes 0.48                                                   |
| `risk_percent`  | Sized so that the master's stop loss would lose `lot_value` percent of the follower's equity | `1` with 5,000 equity risks 50. With the stop 10.00 below a gold entry and 100 oz per lot, one lot would lose 1,000, so the copy is 0.05 lots |

Then:

1. The size is rounded down to the follower broker's lot step and capped at its maximum lot.
2. If it is below the broker's minimum lot, `below_minimum` decides: `minimum` trades the minimum, `skip` skips the trade.
3. If `max_lot` is set, the copy is capped at it.

Notes on the modes:

* `risk_percent` needs a stop loss: the master's trades without one are skipped.
* `balance_ratio` and `equity_ratio` compare the two figures as they are, without converting currency. With a master in EUR and a follower in USD, the size is off by the exchange rate.
* `adjust_contract_size` applies to `multiplier`, `balance_ratio` and `equity_ratio`. Brokers size the same instrument differently: gold can be 100 oz a lot at one broker and 10 oz at another. With `adjust_contract_size` on, a master lot of 100 oz counts as 10 follower lots of 10 oz each, and the mode's own factor applies on top.

## Direction and stops [#direction-and-stops]

* `reverse: true` sells when the master buys and buys when it sells, and swaps stop loss and take profit.
* `copy_stops: true` copies the master's stop loss and take profit, and every later change to them. A new copy opens with them.

## Execution [#execution]

* `max_slippage_pips` limits how far the price may move between the request and the fill. `null` leaves it to the broker.
* `max_delay_seconds` sets how old a master trade may be and still get copied, for example after a terminal reconnects. Older trades are skipped.
* `copy_existing: true` also copies the positions the master already has open when the follower is attached. It doesn't apply when a follower or its copier is resumed: what the master opened during a pause is never copied.

## Pending orders [#pending-orders]

With `copy_pending: false`, the default, a master's pending order is copied when it fills, as a market order.

With `copy_pending: true`, each pending order the master places is placed on the follower too:

* It has the same type and price, and the master's stop loss and take profit. Its size follows the follower's rules. With `reverse`, it is the opposite type at the same price, with the stops swapped: a buy limit becomes a sell stop.
* When the master moves its order, the follower's order moves with it. When the master cancels its order, or the order expires, the follower's order is cancelled. The expiry time is copied too if the follower's broker accepts it. If not, the follower's order stays until the master's expires.
* When the follower's order fills, that position is the copy and follows the master from then on.
* If the master's order fills and the follower's hasn't filled within 2 seconds, the follower's order is cancelled and the copy opens at the market. If the follower's order fills just as it is being cancelled, the follower still ends up with exactly one copy of the trade.
* Orders the master already has when the follower is attached are left alone, unless `copy_existing` is set. Orders the master places during a pause are never placed on the follower. If one fills after the pause, that fill is copied like any new trade.

Even with `copy_pending`, stop-limit orders are copied only when they fill if the follower is on MT4, which has no stop-limit orders, or uses `reverse`.

If you cancel a follower's pending order by hand, it stays cancelled. Turning `copy_pending` off cancels the follower's pending orders that were placed for the master's.

## Symbols [#symbols]

`symbol_filter` and `symbols` choose which of the master's symbols are copied:

| `symbol_filter` | Copies                                 |
| --------------- | -------------------------------------- |
| `all`           | Every symbol. `symbols` is ignored     |
| `include`       | Only the symbols in `symbols`          |
| `exclude`       | Every symbol except those in `symbols` |

`symbols` holds the master's symbol names. A name also covers the same name with a broker's extra characters: `XAUUSD` also covers `XAUUSD.m`. With `include` or `exclude`, `symbols` can't be empty.

### Matching [#matching]

Brokers name the same instrument differently, so each master symbol is matched to one of the follower broker's symbols, in this order:

1. The follower's own `symbol_map`.
2. The same name.
3. The same name without the broker's extra characters, such as `EURUSD.m` or `US30.cash`.
4. Known aliases, such as `XAUUSD` and `GOLD`.

When several symbols fit, the plain name wins: `US500` over `US500m`. Anything still ambiguous is skipped, never guessed.

The full list of aliases, with examples, is on [copying between MT4 and MT5](/mt4-to-mt5-trade-copier).

### Mapping [#mapping]

Map only the names that don't match by themselves:

```json
{ "symbol_map": { "XAUUSD": "GOLD.pro", "NAS100": "USTEC" } }
```

Keys are the master's symbol names, values the follower's. Each name is up to 32 characters.

## Trading sessions [#trading-sessions]

`sessions` limits when new trades are copied. Each session has the weekdays it applies to and a start and end time:

```json
{
  "sessions": [
    { "days": [0, 1, 2, 3, 4], "start": "07:00", "end": "16:30" },
    { "days": [6], "start": "22:00", "end": "02:00" }
  ],
  "timezone": "Europe/London"
}
```

* `days` are 0 (Monday) to 6 (Sunday).
* `start` and `end` are `HH:MM`, 24-hour. An end before its start runs past midnight, like the Sunday session above. A session can't start and end at the same time.
* Up to 14 sessions. With none, trades are copied at any time.
* Sessions only decide which new trades are copied. Copies that are already open always follow the master's closes and stop loss or take profit changes, at any time.

`timezone` sets which clock the session times use. It is either `broker`, the master broker's server time as its MetaTrader charts show it, or a time zone name such as `Europe/London` or `America/New_York`.

## The follower object [#the-follower-object]

```json
{
  "id": "e2f4a6b8-c0d2-4e46-8a8c-9e0f1a2b3c4d",
  "object": "follower",
  "copier_id": "c7d1e5f2-3a4b-4c6d-8e9f-0a1b2c3d4e5f",
  "account_id": "9b2e7d4c-1a3f-4c8e-b5d6-7e8f9a0b1c2d",
  "account": {
    "id": "9b2e7d4c-1a3f-4c8e-b5d6-7e8f9a0b1c2d",
    "name": "Funded #2",
    "platform": "mt5",
    "server": "ICMarketsSC-Demo",
    "login": 51239876,
    "status": "connected"
  },
  "is_active": true,
  "magic": 1840273951,
  "lot_mode": "multiplier",
  "lot_value": 0.5,
  "adjust_contract_size": true,
  "below_minimum": "minimum",
  "max_lot": 5,
  "reverse": false,
  "copy_stops": true,
  "max_slippage_pips": null,
  "max_delay_seconds": 60,
  "copy_existing": false,
  "copy_pending": false,
  "symbol_filter": "all",
  "symbols": [],
  "sessions": [],
  "timezone": "broker",
  "symbol_map": {},
  "status": {
    "state": "copying",
    "message": "",
    "master_connected": true,
    "follower_connected": true,
    "open_copies": 2,
    "last_event_at": "2026-10-25T14:21:07.430Z",
    "balance": 5000.0,
    "equity": 5031.2,
    "currency": "USD",
    "heartbeat_at": "2026-10-25T14:21:15.002Z",
    "engine_online": true
  },
  "created_at": "2026-10-25T14:09:02.118Z",
  "updated_at": "2026-10-25T14:09:02.118Z"
}
```

| Field                      | Description                                                                                    |
| -------------------------- | ---------------------------------------------------------------------------------------------- |
| `id`                       | The follower's ID, a UUID. It isn't the account's ID                                           |
| `copier_id`                | The copier it belongs to                                                                       |
| `account_id`               | The account that copies                                                                        |
| `account`                  | A summary of that account: `id`, `name`, `platform`, `server`, `login` and `status`            |
| `is_active`                | `false` while it is paused                                                                     |
| `magic`                    | The magic number on every order the copier places for this follower                            |
| Rules                      | Every field of [Rules](#rules)                                                                 |
| `status`                   | The live status from the copier engine. `null` until the engine first reports on this follower |
| `created_at`, `updated_at` | When it was attached and last changed                                                          |

### Status [#status]

The copier engine refreshes `status` on every change, and at least every 15 seconds.

| Field                                    | Description                                                                                                                                                   |
| ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `state`                                  | `starting`, `copying`, `paused` or `error`                                                                                                                    |
| `message`                                | When `state` is `error`, what needs attention. `Paused by Equity Guard.` while [Equity Guard](/docs/equity-guard) holds copying back. Otherwise usually empty |
| `master_connected`, `follower_connected` | Whether the engine is connected to each account's terminal                                                                                                    |
| `open_copies`                            | How many of this follower's copies are open                                                                                                                   |
| `last_event_at`                          | When the engine last acted on this follower, or `null`                                                                                                        |
| `balance`, `equity`, `currency`          | The follower's figures as the engine last saw them. `null` until they arrive                                                                                  |
| `heartbeat_at`                           | When the engine last reported                                                                                                                                 |
| `engine_online`                          | `false` when the engine hasn't reported for 60 seconds. The rest of the status is then out of date                                                            |

## List and read followers [#list-and-read-followers]

`GET /v1/copiers/{copier_id}/followers` lists the copier's followers, oldest first, in the [list format](/docs/limits#pagination). `GET /v1/copiers/{copier_id}/followers/{follower_id}` returns one. Reading the copier itself returns all of them too.

## Change a follower's rules [#change-a-followers-rules]

```bash
curl -X PATCH https://api.algotradertools.com/v1/copiers/c7d1e5f2-3a4b-4c6d-8e9f-0a1b2c3d4e5f/followers/e2f4a6b8-c0d2-4e46-8a8c-9e0f1a2b3c4d \
  -H "Authorization: Bearer $ATT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "lot_value": 0.25, "symbol_map": { "XAUUSD": "GOLD.pro" } }'
```

`PATCH` changes only the fields you send, and the engine picks up the change within seconds. Lists and objects are replaced as a whole: sending `symbols` or `symbol_map` replaces the previous value. The account can't be changed: sending `account_id` fails with the code `immutable`. To copy to another account, attach it as a new follower.

You can also send the whole follower back as you read it, with your changes. Read-only fields such as `id`, `account`, `magic` and `status` are ignored. A field that followers don't have, such as a misspelt `lot_vlaue`, is refused with `validation_failed` and the code `unknown_field` instead of being ignored.

## Pause and resume a follower [#pause-and-resume-a-follower]

```bash
curl -X PATCH https://api.algotradertools.com/v1/copiers/c7d1e5f2-3a4b-4c6d-8e9f-0a1b2c3d4e5f/followers/e2f4a6b8-c0d2-4e46-8a8c-9e0f1a2b3c4d \
  -H "Authorization: Bearer $ATT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "is_active": false }'
```

While a follower is paused, nothing new is copied to it. Copies that are already open stay open, and still follow the master's closes and changes. Resuming with `"is_active": true` copies from that moment on. What the master opened while the follower was paused stays uncopied, also with `copy_existing`.

[Equity Guard](/docs/equity-guard#paused-followers) can pause a follower too. That pause shows in the follower's `status`, not in `is_active`, and you resume it in the app.

## Remove a follower [#remove-a-follower]

```bash
curl -X DELETE "https://api.algotradertools.com/v1/copiers/c7d1e5f2-3a4b-4c6d-8e9f-0a1b2c3d4e5f/followers/e2f4a6b8-c0d2-4e46-8a8c-9e0f1a2b3c4d?close_positions=true" \
  -H "Authorization: Bearer $ATT_API_KEY"
```

`close_positions=true` (or `1`) closes the follower's copies at market before it is removed. Without it, or with `false` (`0`), they stay open as ordinary positions that the copier no longer manages. Any other value fails with `validation_failed`. If a terminal refuses to close them, the request fails with `close_failed` (`502`, `503` or `504`). The follower is kept but paused, so nothing new is copied while you decide what to do.

When the removal succeeds, the response is `204 No Content`. Removing a follower deletes its [events](/docs/events). The account stays connected.
