Trader
Tools

Copy events

Read what the copier engine did on each follower, such as opens, closes, stop changes and skipped trades, with the terminal's reply and timings.

View as Markdown

Copy events are the copier's log of what happened on each follower. Every time the copier engine acts on a follower, or decides not to, it records an event: a copy opened, closed in full or in part, its stop loss or take profit changed, a master trade skipped, or a copy recovered after a restart. Events are kept for 90 days. To read them, your API key needs the copiers:read scope.

List a copier's events

curl "https://api.algotradertools.com/v1/copiers/c7d1e5f2-3a4b-4c6d-8e9f-0a1b2c3d4e5f/events?limit=20" \
  -H "Authorization: Bearer $ATT_API_KEY"
Query parameterDescription
follower_idOnly this follower's events
limit1 to 100 events per page, default 50
cursorThe next_cursor of the previous page

Events come newest first, in the list format:

{
  "object": "list",
  "data": [
    {
      "id": 48214,
      "object": "copy_event",
      "follower_id": "e2f4a6b8-c0d2-4e46-8a8c-9e0f1a2b3c4d",
      "account_id": "9b2e7d4c-1a3f-4c8e-b5d6-7e8f9a0b1c2d",
      "master_ticket": 3518820457,
      "action": "skip",
      "ok": true,
      "message": "Opened outside this follower's trading sessions.",
      "detail": { "symbol": "XAUUSD", "volume": 1.0, "side": "sell" },
      "received_at": "2026-10-25T21:04:12.559Z",
      "engine_ms": null,
      "execution_ms": null,
      "total_ms": null
    },
    {
      "id": 48213,
      "object": "copy_event",
      "follower_id": "e2f4a6b8-c0d2-4e46-8a8c-9e0f1a2b3c4d",
      "account_id": "9b2e7d4c-1a3f-4c8e-b5d6-7e8f9a0b1c2d",
      "master_ticket": 3518820446,
      "action": "open",
      "ok": true,
      "message": "Opened 0.48 XAUUSD (buy) at 2391.84.",
      "detail": {
        "symbol": "XAUUSD",
        "side": "buy",
        "volume": 0.48,
        "stopLoss": 2380.0,
        "takeProfit": null,
        "price": 2391.84,
        "retcode": 10009,
        "outcome": "applied",
        "ticket": 3518820991
      },
      "received_at": "2026-10-25T14:21:07.211Z",
      "engine_ms": 0.31,
      "execution_ms": 186.4,
      "total_ms": 186.7
    }
  ],
  "has_more": true,
  "next_cursor": "WyIyMDI2LTEwLTI1VDE0OjIxOjA3LjIxMTAwMCswMDowMCIsICI0ODIxMyJd"
}

The copy event object

FieldDescription
idThe event's ID, an integer
follower_idThe follower it happened on
account_idThat follower's account
master_ticketThe ticket of the master position it is about
actionWhat the engine did. See Actions
okfalse when the action failed
messageWhat happened, in a sentence: the size and price of an open, or why a trade was skipped or failed
detailThe request and the terminal's reply. See Detail
received_atWhen the master's change reached the engine
engine_ms, execution_ms, total_msHow long it took. See Timings

Actions

actionMeaning
openA copy of a new master position was opened or failed to open, or the follower's pending order filled and became the copy
closeA copy was closed. Either the master's position closed, or the copy was closed on the follower account itself: by its stop loss or take profit, by hand, or by Equity Guard
partial_closePart of a copy was closed, in proportion to what the master closed
modifyA copy's stop loss or take profit was changed to follow the master, or the follower's pending order was moved with the master's
skipA master trade wasn't copied, and message says why
adoptAfter a restart, the engine found a copy on the follower that it had no record of, and took it over
placeA pending order was placed on the follower for the master's, or placing it failed. See Pending orders
cancelThe follower's pending order was cancelled. Either the master's order was cancelled, expired or filled without the follower's, or copy_pending was turned off

A trade is skipped, for example, when:

  • the symbol isn't one the follower copies,
  • no follower symbol matches,
  • the trade opens outside the follower's sessions,
  • its size is below the broker's minimum and below_minimum is skip,
  • the follower uses risk_percent and the master's trade has no stop loss,
  • the trade is older than max_delay_seconds,
  • or Equity Guard has copying paused.

Detail

detail holds what was sent to the follower's terminal and what the terminal answered. Its keys depend on the action. For a skip, it describes the master's position instead. Some of the keys:

KeyDescription
symbol, side, volumeThe symbol, buy or sell, and the lots
typeA pending order's type, such as BuyLimit
priceThe price it was filled or closed at
ticketThe copy's ticket on the follower
stopLoss, takeProfitThe stops sent with the order or the change
retcode, outcomeThe terminal's return code and its outcome, such as applied
timingWhere the copy's time went outside the engine. See Timings

Timings

FieldMeasures
engine_msFrom the master's change reaching the engine to the follower's order going out
execution_msFrom the order going out to the follower's terminal answering: mostly the broker's own execution
total_msBoth together

All three are null for events that sent no order, such as skips. They don't include the time MetaTrader takes to report the master's trade. detail.timing adds that, and more, as far as the terminals report it:

KeyDescription
masterFilledAtWhen the master's trade filled, in UTC
masterSentAtWhen the master's terminal reported the trade
masterBridgeMsFrom masterFilledAt to masterSentAt
masterToEngineMsFrom the master's terminal sending the report to the report reaching the engine
bridgeQueueMs, bridgeExecMsInside the follower's terminal: the wait before it takes the order, then the broker's execution
filledAtWhen the copy filled, in UTC
fillToFillMsFrom the master's fill to the copy's

A key is there only when the terminals report the data it needs. An MT5 master's terminal often reports a trade's fill only after the copy is done. So masterFilledAt, masterBridgeMs and fillToFillMs can be added a few seconds after the event first appears. The brokers' clocks and the engine's clock differ by a few milliseconds, so figures measured across two clocks are accurate to a few milliseconds at best.

Page through older events

While has_more is true, pass next_cursor back as cursor for the next, older page:

const copierId = "c7d1e5f2-3a4b-4c6d-8e9f-0a1b2c3d4e5f";
let cursor: string | null = null;
do {
  const query = new URLSearchParams({ limit: "100", ...(cursor ? { cursor } : {}) });
  const page = await att("GET", `/copiers/${copierId}/events?${query}`);
  for (const event of page.data) {
    if (!event.ok) console.log(event.received_at, event.action, event.message);
  }
  cursor = page.has_more ? page.next_cursor : null;
} while (cursor);

The examples use the att helper from the Quickstart. The Python one also needs from urllib.parse import urlencode.

To follow new events as they happen, poll the first page every few seconds and stop at the newest id you have already seen.

Removing a follower deletes its events, and deleting a copier deletes all of the copier's events.

On this page