How trades are mirrored
The full replication path from a leader's order to a follower's fill — the gates, the in-memory queue and its database backstop, the three sizing formulas, how market orders are priced, and the binary fairness window.
A leader places an order. Somewhere between a few hundred milliseconds and two minutes later, every eligible follower holds their own order on the same market. This page is what happens in between, and every point at which a copy can be deliberately skipped.
The gates a leader order passes
The hook fires on order placement and returns quietly — not as an error — if any of these is false. The leader's own order is never affected by any of them.
-
Spot copying is available.
copyTradingEnableSpotmust be on. Before this check existed, the kill switch only blocked new subscriptions while live replication kept moving money. -
The user is an
ACTIVEleader. Anyone else is skipped silently. -
The leader offers this instrument class. A
BINARY-only leader's spot orders are not replicated. -
The leader has at least one
ACTIVEfollower. No followers, no work.
Only then is a leader-trade row written, with status PENDING and — critically —
the leader's own ecosystem order id stored on it. That id is the linkage key
for everything downstream: deduplication, teardown when the leader cancels, and
reconciliation. A leader trade that somehow arrives without one is refused rather
than replicated, because a copy created from it could never be matched back,
cancelled or reconciled.
Two writers, one key
The live queue. The leader-trade row is pushed onto an in-memory queue that drains every 100 ms, one leader trade per tick, fanning out to ten followers concurrently. A task that throws is retried three times with a growing delay. The queue warns past 1,000 pending tasks.
The database backstop. A cron job runs every 10 seconds and picks up leader
trades still PENDING after two minutes — the case where the process restarted
before the queue drained. It takes 50 at a time, three followers at a time, and
stops taking new trades after 60 seconds so a large batch cannot starve every later
tick.
Both write copies keyed on (followerId, leaderOrderId). Whichever runs second
finds the existing copy and stops, counting it as a deliberate skip rather than a
failure. This is what stops a follower being charged twice for one leader action.
If a follower copy genuinely fails, the leader trade is left PENDING and retried,
with the attempt count persisted on the row. After five attempts it is parked
as REPLICATION_FAILED for manual review. A momentary error — a dropped connection,
a brief database hiccup — costs one attempt, not the whole trade.
Sizing a spot copy
Each follower's copy is computed inside a SERIALIZABLE transaction that holds row
locks on the follower, their allocation for that market, and their COPY_TRADING
wallet. Nothing else can spend the same budget while it runs.
Available budget depends on the side, because the two sides of an allocation fund opposite directions:
| Leader side | Spends | Available |
|---|---|---|
BUY |
Quote currency | quoteAmount − quoteUsedAmount |
SELL |
Base currency | baseAmount − baseUsedAmount |
Then the mode decides the quantity:
leaderPercent = (leaderAmount × leaderPrice) / leaderQuoteBalance
copyAmount = (available × leaderPercent) / leaderPricecopyAmount = fixedAmount / leaderPricecopyAmount = leaderAmount × fixedRatio (fixedRatio defaults to 0.1)leaderQuoteBalance is the leader's ECO wallet balance in the quote currency,
read once when the leader trade is created. If it cannot be read or is zero, a
PROPORTIONAL copy is skipped with "Leader balance unknown" — the other two modes
are unaffected.
Two clamps follow, in order:
- Max position size, applied as a ceiling on the quantity in base units (see the warning in Following a trader).
- The remaining allocation. If the resulting cost exceeds what is available, the quantity is reduced until it fits. A copy can never overspend its allocation.
Why a copy gets skipped
Every one of these is a normal, logged outcome — not an error, and not something to fix unless it is happening constantly.
| Reason | Means |
|---|---|
| No spot allocation for this market | The follower has not allocated on the symbol the leader just traded |
Insufficient allocation for BUY / SELL |
The relevant side is fully committed to open orders |
| Leader balance unknown | PROPORTIONAL mode and the leader's quote balance read as zero |
| Fixed amount not configured | FIXED_AMOUNT mode with no amount set |
| Amount below minimum | The computed quantity is under the ecosystem market's own minimum order size |
| Daily trade limit reached / Daily loss limit reached | The follower's own caps — checked on both writers |
| Insufficient balance | The COPY_TRADING wallet cannot cover cost plus fee |
| Follower is not active | Paused or stopped between the leader's order and the fan-out |
Pricing and holding
A limit copy uses the leader's price. A market copy does not.
The matching engine walks resting orders and may cross several levels, so the average fill is at least the best level and usually worse. Holding funds at the top level under-holds — and settlement's locked-funds guard then refuses the fill and rolls it back, leaving the follower with an order that can never complete while their money stays locked.
Copy trading therefore walks the book for the quantity it is about to place and uses the average price across the levels it would actually consume. When the book cannot cover the size it falls back to the deepest real level, so the hold always errs high. Only real, order-backed levels are considered — synthetic market-maker levels cannot be filled against.
The fee is the market's own taker rate applied to quantity × effective price, rounded to the market's price precision, and is always denominated in the quote currency. Two figures come out of that and they are not the same:
- Order cost is fee-exclusive —
quantity × pricefor a buy, the quantity itself for a sell. This is what is stored on the order, so the matching engine's own cost-plus-fee arithmetic matches an ordinary ecosystem order. - Total cost is what is actually locked — order cost plus fee for a buy, the base quantity for a sell.
The order is created against the COPY_TRADING wallet type, funds are moved from
balance into inOrder, the copy-trade row is written with its measured latency, and
the allocation's committed figure is increased. Only after that transaction commits
is the order pushed onto the matching queue — enqueuing first would leave an order
the engine tries to match against a wallet hold that no longer exists.
If the transaction rolls back after the order row was written, the order is deleted as compensation. Otherwise it would sit unfunded and be reloaded by the engine on restart.
What happens after the fill
| Event | Handled by |
|---|---|
| A partial or full fill | The fill monitor syncs the copy's status and accumulates executed quantity and fee across fills |
| A stop-loss or take-profit level is hit | The stop monitor cancels the unfilled remainder and places a real opposite market order; the trade reads CLOSING, then CLOSED |
| The leader cancels their order | Every follower copy on that leaderOrderId is torn down — order cancelled, hold released, allocation freed |
| A copy closes with realised profit | Profit share and the platform fee are settled — see Fees and profit share |
| The order was cancelled or vanished out of band | The reconciler, every five minutes, tears the copy down and releases the stranded hold |
The reconciler only considers copies older than two minutes, so it never races a fill still in flight. It is release-only and safe to re-run.
Binary copying
The binary path shares the sizing modes and the risk caps but almost nothing else.
A copy inherits the leader's frozen contract terms — barrier, strike, payout — while being placed at the current market price. That combination is only fair while the leader's order is fresh, which is why the engine enforces hard bounds:
| Bound | Value | Why |
|---|---|---|
| Maximum staleness | 90 seconds | Replaying an older order hands followers a contract whose outcome is already largely decided, and would let a leader select winners by activating a market late |
| Minimum time to expiry | 15 seconds | A contract too close to expiry to be fair is skipped rather than copied |
| Fan-out lock | 120 seconds | One leader order's fan-out at a time; if the process dies the lock expires and the backstop picks it up |
| Backstop minimum age | 8 seconds | Lets the live path win before the backstop steps in |
The copy engine used to invent 85% when the leader's order carried no payout percentage — a number that is not configurable and is above the platform default, so every affected copy paid a winning follower more than the product was sold for.
A follower must be sold the same contract as the leader. A leader order with no payout rate to copy is now skipped with a recorded reason. Core no longer produces such orders.
Stake sizing runs the same three modes against the allocation's stake budget, then
applies max position size as a genuine percentage of that budget, then the
platform-wide copyTradingBinaryMaxStake hard cap, then whatever is left in the
budget.
The money model is deliberately different from spot. The binary engine holds the stake at placement and releases or consumes it at expiry, so copy trading never moves principal for an open order. Copying follows a strict reserve → place → book order: the stake is reserved out of the budget before the order is placed, the order is placed from the COPY_TRADING wallet, then the placed order's real amount is reconciled back. Two leader orders arriving at the same instant therefore cannot spend the same free budget.
Every placement carries an idempotency key built from the leader's order id and the follower's id, so the live path, the backstop and any retry converge on a single order.