Copy Trading Across Your MetaTrader 5 Accounts with an API
Mirror one master MetaTrader 5 account's trades to many followers — each scaled, symbol-mapped, and risk-clamped to its own size — over a REST API. Create a set, tune the sizing and guards, arm it. TypeScript and Python examples.
Say you run one strategy but several accounts: a demo you trust, a couple of funded/prop accounts, maybe one on a different broker. You want them to move together — when the strategy fires on the master, every other account takes the same trade, each sized to its own equity and clamped to its own risk limits.
That's Copy Trading: one master account whose fills are mirrored to a set of followers. TickerAll's copy engine is self-copy — the master and every follower are your own accounts. It is not a social/marketplace product where you follow strangers; it's a way to fan your own trading across your own roster, programmatically.
Copy Trading is a Pro / Enterprise feature. Every
/v1/copy/*call requires a Pro or Enterprise plan; on Free and Trader it returns403(COPY_REQUIRES_PRO). Self-copy only — the master and all followers must be your own accounts, and a follower can't also be the master.
The shape of it
A copy set is one master account plus N followers. The workflow is always the same: create the set (with followers inline or added later), tune each follower's sizing and guards, then arm it. A set is created paused — nothing mirrors until you arm it — so you can get the followers right before a single trade copies.
Install
npm install @tickerall/sdk # TypeScript / Node 18+
pip install tickerall # Python 3.9+
Create a set
import { Tickerall } from '@tickerall/sdk'
const client = new Tickerall({ apiKey: process.env.TICKERALL_API_KEY! })
const set = await client.copy.createSet({
name: 'My desk',
masterAccountId: 'acc_master',
followers: [
{ followerAccountId: 'acc_demo', sizingMethod: 'proportional' }, // scale by equity ratio
{ followerAccountId: 'acc_prop1', sizingMethod: 'multiplier', sizingValue: 0.5 }, // half the master's size
{ followerAccountId: 'acc_prop2', sizingMethod: 'risk_percent', sizingValue: 1 }, // risk 1% per trade
],
})
await client.copy.arm(set.id) // start mirroring (pause again with client.copy.pause)
from tickerall import Tickerall
client = Tickerall(api_key="cf_live_...")
s = client.copy.create_set(
"My desk", "acc_master",
followers=[
{"follower_account_id": "acc_demo", "sizing_method": "proportional"},
{"follower_account_id": "acc_prop1", "sizing_method": "multiplier", "sizing_value": 0.5},
{"follower_account_id": "acc_prop2", "sizing_method": "risk_percent", "sizing_value": 1},
],
)
client.copy.arm(s.id) # start mirroring (pause again with client.copy.pause)
Sizing: how a follower's volume comes from the master's
Every follower picks one sizingMethod. sizingValue means something different
for each — that's the field to get right.
sizingMethod |
What the follower trades | sizingValue |
|---|---|---|
proportional (default) |
The master's volume scaled by the follower ÷ master equity ratio — a €5k follower behind a €50k master trades a tenth the size, automatically. | not used |
multiplier |
The master's volume × a fixed factor. | the factor (e.g. 0.5 = half, 2 = double) |
fixed |
The same fixed lot size on every copied trade, regardless of the master's. | the lot size (e.g. 0.10) |
risk_percent |
A volume sized so the trade's stop-distance risks a set percentage of follower equity. | the risk % (e.g. 1 = 1%) |
The computed volume is then snapped to the follower broker's lot step and clamped
by minLot / maxLot.
Risk guards: what a follower will refuse to copy
Sizing decides how big; the guards decide whether to copy at all and within what limits. All are per-follower and optional.
| Guard | Effect |
|---|---|
minLot / maxLot |
Clamp and snap the copied volume to the follower broker's lot step. |
maxOpenTrades / maxExposureLots |
Caps — stop copying once the follower is at its open-trade or total-lots ceiling. |
symbolAllow / symbolBlock |
Allow-list / block-list of follower symbols (string arrays). |
dailyLossStop |
Auto-pause the follower once its loss for the day crosses this. |
reverse |
Inverse copy — the follower sells when the master buys. |
maxSlippagePips |
Skip the copy if the follower's price has moved too far from the master's fill. |
minMasterLot |
Ignore the master's tiny trades below this size. |
copyDelayMs |
Delay each copy by this many milliseconds. |
symbolOverrides |
A { "MASTERSYMBOL": "followerSymbol" } map for cross-broker names the auto-normalizer can't resolve on its own. |
symbolOverrides is the one that saves cross-broker desks. The engine normalizes
common naming differences automatically (BTCUSD ↔ BTCUSDm), but if a master
symbol has no obvious follower equivalent, map it explicitly:
await client.copy.addFollower(set.id, {
followerAccountId: 'acc_xm',
sizingMethod: 'multiplier',
sizingValue: 1,
symbolOverrides: { 'BTCUSDm': 'BTCUSD', 'XAUUSDm': 'GOLD' },
maxSlippagePips: 3,
})
Tune followers after the fact
Add, update, or remove followers on a live set — a PATCH changes only the fields you pass.
await client.copy.addFollower(set.id, { followerAccountId: 'acc_prop3', reverse: true, maxSlippagePips: 3 })
await client.copy.updateFollower(set.id, 'follower_id', { maxLot: 1, symbolBlock: ['XAUUSD'] })
await client.copy.removeFollower(set.id, 'follower_id')
client.copy.add_follower(s.id, "acc_prop3", config={"reverse": True, "max_slippage_pips": 3})
client.copy.update_follower(s.id, "follower_id", {"max_lot": 1, "symbol_block": ["XAUUSD"]})
client.copy.remove_follower(s.id, "follower_id")
Arm, pause, and watch it work
arm and pause flip the whole set on and off. Pausing stops new mirroring;
existing follower positions are left exactly as they are.
await client.copy.arm(set.id) // mirror from now on
await client.copy.pause(set.id) // stop mirroring; leave open positions alone
Two read endpoints tell you how it's going. Stats is the dashboard rollup; the log is the per-action audit trail.
const stats = await client.copy.getStats(set.id)
console.log(stats.totals) // { ok, skipped, failed, replicationRate }
for (const f of stats.followers) {
console.log(f.followerAccountId, 'ok', f.ok, 'skipped', f.skipped, 'open', f.openPositions)
}
// Every mirrored action, newest first; page with `before` + `limit` (max 200)
const page = await client.copy.getLog(set.id, { limit: 50 })
for (const e of page.entries) {
console.log(e.action, e.followerAccountId, e.result, e.reason ?? '')
}
// page.nextBefore -> pass as `before` for the next page, or null at the end
stats = client.copy.get_stats(s.id)
print(stats.totals.ok, stats.totals.skipped, stats.totals.failed, stats.totals.replication_rate)
page = client.copy.get_log(s.id, limit=50)
for e in page.entries:
print(e.action, e.follower_account_id, e.result, e.reason or "")
# page.next_before -> pass as `before` for the next page, or None at the end
A log entry with result: 'skipped' and a reason is exactly how you learn a
guard did its job — a copy skipped for maxSlippagePips, symbolBlock, or
maxOpenTrades shows up here, not as a silent no-op.
Optional: get pushed every outcome
If you'd rather be told than poll, attach a webhook when you create or update the
set. Every mirror outcome then POSTs to your webhookUrl with an HMAC-SHA256
signature in the X-Tickerall-Signature header, keyed by your webhookSecret
(16+ characters, write-only — it's never returned).
await client.copy.updateSet(set.id, {
webhookUrl: 'https://your-app.example.com/hooks/copy',
webhookSecret: process.env.COPY_WEBHOOK_SECRET!,
})
Validate on demo followers first
Sizing math is the part worth proving before real money is on the follower side.
Point the master at your strategy and make the followers demo accounts to
start: place a trade, then read getStats / getLog and confirm each follower
took the size you expected — proportional scaling landed where you thought, the
multiplier and risk-percent followers came out right, and the guards skipped what
they should. Once the numbers match your intent, swap in the real followers.
Where to go next
Copy Trading is "mirror whatever the master does." If instead you want to push the same explicit action to many accounts at once — place, close, or read across a roster in one call — that's the Bulk API. New to the SDK? The TypeScript quickstart covers a single account end to end.
Full API reference: tickerall.com/docs