View as Markdown

Build a trade copier

Copy trades from one account to many, with idempotency keys so a retry never fills twice, and handle the ones that can't be confirmed.

Copiers fail in two ways: copying a trade twice, or silently not copying it. Here’s how to avoid both.

Copy only into accounts whose owners have authorised it. Copying into someone else’s account is banned by our acceptable use policy and by most prop firms.

Listen to the source

Subscribe to the source account’s stream and act on position changes:

if (f.type === "positionUpdated" && isNew(f.position)) fanOut(f.position);
if (f.type === "positionRemoved") closeCopies(f.positionId);

Fan out with deterministic keys

Derive the idempotency key from the source position and the follower. A crashed and restarted worker then produces the same key and can’t double-copy.

import requests

def copy_open(follower, src):
    return requests.post(
        f"{TW}/users/current/accounts/{follower}/trade",
        headers={
            "auth-token": KEY,
            "Idempotency-Key": f"open-{src['id']}-{follower}",
            "X-Actor": "copier",
            "X-Reason": f"copy of {src['id']}",
        },
        json={
            "actionType": "ORDER_TYPE_BUY" if src["type"] == "POSITION_TYPE_BUY" else "ORDER_TYPE_SELL",
            "symbol": map_symbol(follower, src["symbol"]),
            "volume": size_for(follower, src),
            "clientId": f"cp_{src['id']}",
        },
        timeout=30,
    ).json()

clientId is stored with the order, so you can find each copy later by the source id.

Symbols differ per broker

EURUSD on one broker is EURUSDm or EURUSD.r on another. Build a map per follower from GET …/symbols, and check symbols/{symbol}/specification for minVolume and volumeStep before sizing. Cent accounts need very different volumes.

Many followers in one call

POST /v1/orders sends up to 20 legs across accounts in one idempotent request and returns a status per leg.

Handle “unknown”

If a leg comes back unknown, don’t send a new order. Retry with the same key, or look for the clientId in the follower’s positions. See Idempotency.

Skip followers you can’t reach

Check health before copying. If a follower is disconnected, record the missed copy and decide deliberately (catch up at market, or skip) when it comes back, rather than letting requests time out.