Referral rewards on copy-trading subscriptions
The affiliate commission copy trading pays when a referred user subscribes to a leader — what triggers it, what the reward is a percentage of, where to configure it, and why the base figure is unreliable.
Copy trading pays an affiliate commission. It is easy to miss, because nothing on any copy-trading screen mentions it: the trigger lives in the subscribe endpoint, the configuration lives in the affiliate addon, and the two never refer to each other.
If you run a referral programme, this is a live cost line on every subscription.
What fires, and when
One call, from one place: the subscribe endpoint, after the subscription and all its wallet transfers have committed.
| Condition name | COPY_TRADING |
| Paid to | The referrer of the subscribing user |
| Fires | Once per subscription, at subscribe time |
| Reward base | The sum of every market allocation in the request |
| Currency passed | The literal string USD |
| Source id | COPY_TRADING:follower:{followerId} |
It fires once, when somebody subscribes. It does not fire on copied volume, on realised profit, on a top-up to an existing allocation, on adding a market to an existing subscription, or on anything the follower does afterwards. A follower who subscribes and never has a single trade copied still earns their referrer the full commission.
There is no path anywhere in the addon that pays a referrer on ongoing copy-trading activity. Design the programme around that.
The reward is recorded against the source id COPY_TRADING:follower:{followerId},
which carries a unique index, so it is deduplicated per subscription. A retried
request cannot pay twice. On a BINARY or UNILEVEL structure each upline level gets
its own suffixed id (…:L1, …:L2), so the same protection applies per level.
The reward base, and why it is unreliable
The endpoint sums quoteAmount + baseAmount across every allocation in the
subscribe request, then passes that number to the affiliate engine with the currency
literal "USD".
Nothing converts it. Nothing checks that the assets are comparable.
A follower who allocates 500 USDT on BTC/USDT gets a base of 500 — reasonable.
A follower who allocates 0.01 BTC and 200 USDT on the same market gets
0.01 + 200 = 200.01, and the ~$600 of BTC contributes one hundredth of a unit. A
follower who allocates 2 ETH and nothing else gets a base of 2, and — because the
shipped condition has a 50 minimum — earns their referrer nothing at all.
The rate you set is applied to that number and paid out in the condition's own
rewardCurrency (USDT by default). So on a book that is genuinely multi-asset, the
commission bears no stable relationship to what the follower actually committed.
This is a defect to design around, not a setting to fix. Two practical mitigations: run leaders on quote-only allocations where you can, and set the rate against the typical quote allocation size on your busiest markets rather than against an average that base-side allocations have distorted.
The threshold that is in the comment, and the one that is real
The subscribe endpoint's comment says "Minimum threshold: 50 USD equivalent total
allocation". The endpoint does not implement that. Its only guard is
totalAllocation > 0; any allocation at all reaches the affiliate engine.
The real minimum lives one layer down, on the condition itself. The affiliate engine
compares the base against the condition's minAmount and returns without paying if
it is lower. COPY_TRADING ships with minAmount = 50, so on a default install
a 50-unit floor does bind — it simply is not the copy-trading code enforcing it,
it is editable per condition, and it is compared against the unconverted mixed-asset
number described above.
If you change or remove minAmount, nothing in copy trading will stop a one-unit
allocation from earning a commission.
Where to configure it
Everything is on Admin → Affiliate → Conditions (/admin/affiliate/condition),
in the mlm_referral_condition table. Two rows are relevant.
| Row | Ships | Seeded values | Fires |
|---|---|---|---|
COPY_TRADING |
Enabled | 3%, minAmount 50, paid in SPOT / USDT |
Yes — this page |
COPY_TRADING_PROFIT |
Disabled | 1%, minAmount 5 |
Nothing calls it |
COPY_TRADING seeds with status enabled and a 3% percentage reward. It is one of
fifteen conditions active out of the box.
Existing installs are untouched by upgrades — the seeder skips by name — so whatever your operator chose previously still stands. Check the row before assuming either state.
To change what you pay, edit the COPY_TRADING row:
rewardandrewardType— aPERCENTAGEof the base, or aFIXEDamount per subscription. A fixed amount sidesteps the unreliable base entirely and is worth considering for exactly that reason.minAmount— the floor, compared against the base described above.rewardWalletTypeandrewardCurrency— where the commission lands and what it is denominated in.SPOT/USDTby default.status— off pays nothing and hides the rule from the members' commission rates page.period— ignored.COPY_TRADINGis event-driven, so the calendar window never applies to it.
name is a key, not a label. The engine looks the condition up by name and rejects
any name it does not recognise, so renaming the row silently switches the commission
off. Use title and description for member-facing wording.
Nothing in the platform calls processRewards with that name, so it is not
event-driven — which means the hourly affiliate evaluator picks it up instead. That
evaluator resolves the COPY_TRADING condition type to EXCHANGE_ORDER ledger
transactions.
Enable it and you will not be paying on copy-trading profit. You will be paying a
recurring percentage of your referred users' exchange order volume, stacked on top
of whatever SPOT_TRADE already pays on the same fills.
Leave it off unless that is genuinely what you want.
Prerequisites, and the failure mode you will not see
Three things have to be true before a single reward is written:
- The
mlmextension is enabled. If it is not, the engine returns immediately and nothing is recorded — no error, no log line at the copy-trading end. - The
COPY_TRADINGcondition exists with status enabled. If not, the engine logsReferral condition not found or inactive: COPY_TRADINGat warn level and returns. - The subscribing user has an
ACTIVEreferral row naming a referrer. APENDINGreferral — which is what every new referral is whenaffiliateRequireApprovalis on — earns nothing, and nothing back-pays it once it is approved.
Who is paid depends on the MLM structure. Under DIRECT it is the one referrer.
Under BINARY or UNILEVEL the engine walks the sponsor chain — who invited
whom, from mlmReferral.referrerId — and pays each configured level a share of the
condition's reward. Tree placement and spillover do not change who gets paid.
The whole call is wrapped in try/catch with a bare console.error. A failure
never blocks the subscription, never rolls it back, and never surfaces anywhere an
operator looks — not on the copy-trading dashboard, not in
copy_trading_audit_logs, not on the subscription row.
A subscription that paid no commission and a subscription that paid one look
identical from the copy-trading side. The only place to check is
Admin → Affiliate → Rewards (/admin/affiliate/reward), filtered by the
COPY_TRADING condition, cross-referenced against subscriptions created in the same
window on /admin/copy-trading/follower.
Do that check after any change to the affiliate configuration, and after any upgrade.
What happens once a reward exists
The row is written unclaimed. One notification actually goes out: the referrer
gets "Referral Reward Earned" linking to /affiliate/reward.
An administrator notification — "MLM Reward Processed", linking to
/admin/affiliate/reward — is attempted as well, but it never reaches anybody. The
reward code asks for recipients by the permission name View MLM Rewards, and no
such permission exists: permission names on this platform are dotted keys, and the
affiliate reward ones are access.affiliate.reward, view.affiliate.reward,
create.affiliate.reward, edit.affiliate.reward and delete.affiliate.reward. The
lookup matches no permission row, so the fan-out resolves to zero administrators and
sends nothing. You cannot grant your way onto that list — the name is not grantable,
so no administrator is ever told a reward was written. Watch the Rewards screen
instead.
The money is not credited at that point. The referrer claims it themselves, and the
claim credits the condition's rewardWalletType wallet in its rewardCurrency,
creating the wallet if they do not have one. An unclaimed reward is a liability you
are carrying, not a payment you have made.
Programme design, in short
- Pay on acquisition. This condition rewards the moment a referral commits capital, and nothing rewards them afterwards. If you want to reward retention, it will not come from here.
- Prefer a fixed reward, or a percentage tuned to quote-only allocations. The percentage base is not a money amount on a multi-asset book.
- Set
minAmountdeliberately. It is the only floor, and it is measured in that same unreliable unit. - Watch the reward table, not the copy-trading screens. Copy trading will never tell you the commission failed.
- Remember the follower can leave immediately. Stopping a subscription returns their capital and does not claw the commission back. A short minimum-allocation floor plus a generous rate is an abusable combination.
Related
- Commission conditions — the two reward engines, the currency trap and the overlap guard
- Following a trader — what an allocation is and where the money comes from
- Admin console — where subscriptions are listed