{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/algotradertools/json-schema/algotradertools-follower-schema.json",
  "title": "Follower",
  "description": "An account that copies a copier's master, with its own rules.",
  "x-generated": "2026-11-08",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/algotradertools-openapi.json#/components/schemas/Follower",
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "description": "The follower's ID.",
      "format": "uuid"
    },
    "object": {
      "type": "string",
      "enum": [
        "follower"
      ],
      "description": "What this object is."
    },
    "copier_id": {
      "type": "string",
      "description": "Its copier.",
      "format": "uuid"
    },
    "account_id": {
      "type": "string",
      "description": "The account that copies.",
      "format": "uuid"
    },
    "account": {
      "$ref": "#/$defs/AccountRef"
    },
    "is_active": {
      "type": "boolean",
      "description": "False while this follower is paused."
    },
    "magic": {
      "type": "integer",
      "description": "The magic number on every order placed for this follower. Each copy's comment is `att:` and the master's ticket in base 36."
    },
    "lot_mode": {
      "type": "string",
      "enum": [
        "multiplier",
        "fixed",
        "balance_ratio",
        "equity_ratio",
        "risk_percent"
      ],
      "description": "How each copy is sized. `multiplier`: the master's lots times `lot_value`. `fixed`: `lot_value` lots on every copy. `balance_ratio` / `equity_ratio`: the master's lots scaled by this account's balance or equity against the master's, times `lot_value`. `risk_percent`: sized so the master's stop loss risks `lot_value` percent of this account's equity; trades without a stop loss are skipped."
    },
    "lot_value": {
      "type": "number",
      "description": "The multiplier, the lot size or the risk percentage, by `lot_mode`. Above 0 and up to 1000; up to 100 for `risk_percent`. Up to four decimal places.",
      "exclusiveMinimum": 0,
      "maximum": 1000
    },
    "adjust_contract_size": {
      "type": "boolean",
      "description": "Even out different contract sizes between the brokers (gold can be 100 oz a lot at one broker and 10 oz at another). Applies to `multiplier` and the ratio modes."
    },
    "below_minimum": {
      "type": "string",
      "enum": [
        "minimum",
        "skip"
      ],
      "description": "When a copy comes out below the broker's minimum lot: trade the minimum, or skip it."
    },
    "max_lot": {
      "type": [
        "number",
        "null"
      ],
      "description": "The most lots one copy may have; null for no limit.",
      "exclusiveMinimum": 0
    },
    "reverse": {
      "type": "boolean",
      "description": "Sell when the master buys and the other way round; stop loss and take profit swap."
    },
    "copy_stops": {
      "type": "boolean",
      "description": "Copy stop loss and take profit, including later changes."
    },
    "max_slippage_pips": {
      "type": [
        "number",
        "null"
      ],
      "description": "The slippage allowed per order; null uses the broker's default.",
      "minimum": 0
    },
    "max_delay_seconds": {
      "type": "integer",
      "description": "How late a master trade may still be copied, for example after a reconnect; older ones are skipped.",
      "minimum": 0,
      "maximum": 3600
    },
    "copy_existing": {
      "type": "boolean",
      "description": "Also copy the positions and pending orders the master already has when the follower is attached. Nothing the master opens or places during a pause is ever copied."
    },
    "copy_pending": {
      "type": "boolean",
      "description": "Place the master's pending orders on the follower as pending orders, and follow their changes, rather than copying them once they fill. Needs both terminals on the current version."
    },
    "symbol_filter": {
      "type": "string",
      "enum": [
        "all",
        "include",
        "exclude"
      ],
      "description": "`all` copies every symbol, `include` only those in `symbols`, `exclude` all but them."
    },
    "symbols": {
      "type": "array",
      "items": {
        "type": "string",
        "maxLength": 32
      },
      "maxItems": 200,
      "description": "The master's symbol names for `symbol_filter`, which needs at least one unless it is `all`. `XAUUSD` also covers decorated names such as `XAUUSD.m`."
    },
    "sessions": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/Session"
      },
      "maxItems": 14,
      "description": "When new trades are copied; empty means any time. Closes and changes to copies already open are always copied."
    },
    "timezone": {
      "type": "string",
      "description": "The clock `sessions` are read on: `broker` (the master broker's server time, as its MetaTrader charts show it) or a time zone name such as `Europe/London`."
    },
    "symbol_map": {
      "type": "object",
      "additionalProperties": {
        "type": "string",
        "maxLength": 32
      },
      "maxProperties": 200,
      "description": "Master symbol to follower symbol, for names that don't match by themselves. Matching tries this map, then the same name, the name without the broker's decorations (`EURUSD.m`, `US30.cash`), then known aliases (`XAUUSD` and `GOLD`); anything still ambiguous is skipped, never guessed."
    },
    "status": {
      "anyOf": [
        {
          "$ref": "#/$defs/FollowerStatus"
        },
        {
          "type": "null"
        }
      ]
    },
    "created_at": {
      "type": "string",
      "format": "date-time"
    },
    "updated_at": {
      "type": "string",
      "format": "date-time"
    }
  },
  "required": [
    "id",
    "object",
    "copier_id",
    "account_id",
    "account",
    "is_active",
    "magic",
    "lot_mode",
    "lot_value",
    "adjust_contract_size",
    "below_minimum",
    "max_lot",
    "reverse",
    "copy_stops",
    "max_slippage_pips",
    "max_delay_seconds",
    "copy_existing",
    "copy_pending",
    "symbol_filter",
    "symbols",
    "sessions",
    "timezone",
    "symbol_map",
    "status",
    "created_at",
    "updated_at"
  ],
  "$defs": {
    "AccountRef": {
      "type": "object",
      "properties": {
        "id": {
          "type": "string",
          "description": "The account's ID.",
          "format": "uuid"
        },
        "name": {
          "type": "string",
          "description": "Its nickname, or the platform and login."
        },
        "platform": {
          "type": "string",
          "enum": [
            "mt4",
            "mt5"
          ]
        },
        "server": {
          "type": "string",
          "description": "The broker's server."
        },
        "login": {
          "type": "integer",
          "description": "The MetaTrader account number."
        },
        "status": {
          "type": "string",
          "enum": [
            "connecting",
            "connected",
            "error",
            "disconnected"
          ],
          "description": "Whether its terminal is connected."
        }
      },
      "description": "An account as other objects show it. Get the account for the rest.",
      "required": [
        "id",
        "name",
        "platform",
        "server",
        "login",
        "status"
      ]
    },
    "FollowerStatus": {
      "type": "object",
      "properties": {
        "state": {
          "type": "string",
          "enum": [
            "starting",
            "copying",
            "paused",
            "error"
          ],
          "description": "`starting` while the engine connects, `copying`, `paused` (the follower or its copier is paused, or Equity Guard holds copying back), or `error` (see `message`)."
        },
        "message": {
          "type": "string",
          "description": "Why it needs attention, or `Paused by Equity Guard.` while Equity Guard holds copying back; empty otherwise."
        },
        "master_connected": {
          "type": "boolean",
          "description": "The engine's stream from the master's terminal is up."
        },
        "follower_connected": {
          "type": "boolean",
          "description": "The engine's stream from this account's terminal is up."
        },
        "open_copies": {
          "type": "integer",
          "description": "Copies open on this account now."
        },
        "last_event_at": {
          "type": [
            "string",
            "null"
          ],
          "description": "When the engine last did something here.",
          "format": "date-time"
        },
        "balance": {
          "type": [
            "number",
            "null"
          ],
          "description": "This account's balance as the engine last saw it."
        },
        "equity": {
          "type": [
            "number",
            "null"
          ],
          "description": "This account's equity as the engine last saw it."
        },
        "currency": {
          "type": "string"
        },
        "heartbeat_at": {
          "type": "string",
          "description": "When the engine last reported; at least every 15 seconds.",
          "format": "date-time"
        },
        "engine_online": {
          "type": "boolean",
          "description": "False when the engine hasn't reported for 60 seconds."
        }
      },
      "description": "What the copier engine reports about a follower, as of `heartbeat_at`.",
      "required": [
        "state",
        "message",
        "master_connected",
        "follower_connected",
        "open_copies",
        "last_event_at",
        "balance",
        "equity",
        "currency",
        "heartbeat_at",
        "engine_online"
      ]
    },
    "Session": {
      "type": "object",
      "properties": {
        "days": {
          "type": "array",
          "items": {
            "type": "integer",
            "minimum": 0,
            "maximum": 6
          },
          "minItems": 1,
          "description": "0 is Monday, 6 Sunday."
        },
        "start": {
          "type": "string",
          "description": "`HH:MM`, 24-hour.",
          "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$"
        },
        "end": {
          "type": "string",
          "description": "`HH:MM`. An end before its start runs past midnight.",
          "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$"
        }
      },
      "description": "A window in which new trades are copied.",
      "required": [
        "days",
        "start",
        "end"
      ]
    }
  }
}