> ## Documentation Index
> Fetch the complete documentation index at: https://docs.0xmonaco.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Copy Trading

> Lead trader profiles, the leaderboard, and your follows

```typescript theme={null}
import { MonacoSDK } from "@0xmonaco/core";

// Public, no session needed
await sdk.copyTrading.listLeadTraders({ sort: "roi", window: "30d" });
await sdk.copyTrading.getLeadTrader(handle);
await sdk.copyTrading.listLeadTraderClosedTrades(handle, { pageSize: 50 });

// Follower
await sdk.copyTrading.upsertFollow({ leader: handle, allocation: "1000" });
await sdk.copyTrading.listMyFollows();
await sdk.copyTrading.getFollow(followId);
await sdk.copyTrading.listLeadTraderOpenPositions(handle);
await sdk.copyTrading.addFollowPositionMargin({ followId, tradingPairId, amount: "25" });
await sdk.copyTrading.stopFollow(followId);
await sdk.copyTrading.closeFollowPositions(followId);
await sdk.copyTrading.closeAllCopyPositions();

// Leader
await sdk.copyTrading.upsertLeadTrader({ shareBps: 1000 });
await sdk.copyTrading.getMyLeadTrader();
await sdk.copyTrading.listMyFollowers();
```

For concepts and a full walkthrough see [Copy Trading](/developers/copy-trading). For live follow state, subscribe to the [`copy` channel](/sdk/typescript/websockets#copy-channel).

Leaders are addressed by their custom TraderCode handle. Every param object is validated client-side before the request is sent, and a failure throws `ValidationError` with no request made. Lists are cursor paged: pass the previous response's `nextPageToken` until it comes back empty. Optional response fields the server has no value for arrive as `null`.

***

<ResponseField name="listLeadTraders" type="(params?: ListLeadTradersParams) => Promise<ListLeadTradersResponse>">
  The public leaderboard, highest first. No session needed.

  **Params:**

  * `sort?`: `"roi"` (default) | `"pnl"` | `"followers"` | `"allocated"` | `"aum"` | `"win_rate"` (`aum` ranks by `aumEquity`, leaders without it last)
  * `window?`: `"7d"` | `"30d"` (default) | `"90d"` | `"all"`
  * `pageSize?`: number — 1 to 100 (default 20)
  * `pageToken?`: string — a previous response's `nextPageToken`, with the SAME `sort` and `window`

  **Returns:** `leaders[]` (each `{ profile, followSummary, stats }` with stats for the requested window), `nextPageToken` (empty at the end) and `asOf` (the leaderboard snapshot time).

  * `profile`: `leader` (`walletAddress`, `handle`, `display`), `status`, `shareBps`, `bio`, `minAllocation`, `registeredAt`
  * `followSummary`: `followerCount`, `allocated` (AUM as allocated, not marked) and `aumEquity?` (AUM marked: the live follows' copy account equity at the engine's marks; absent when it could not be read)
  * `stats`: `window`, `pnl` (realized plus unrealized, net of fees and funding), `roiPct`, `maxDrawdownPct`, `winRatePct`, `closedTrades`
</ResponseField>

<ResponseField name="getLeadTrader" type="(handle: string) => Promise<GetLeadTraderResponse>">
  One leader by custom TraderCode handle: `profile`, `followSummary`, and `stats` for every window (7d, 30d, 90d, all). No session needed. 404 for an unknown or suspended leader.
</ResponseField>

<ResponseField name="listLeadTraderClosedTrades" type="(handle: string, params?: { pageSize?: number; pageToken?: string }) => Promise<ListLeadTraderClosedTradesResponse>">
  A leader's reducing executions — partial and full closes, liquidations and auto-deleveraging — newest first. No session needed. `pageSize` is 1 to 100.

  **Returns:** `closedTrades[]` (`tradingPairId`, `positionSide`, `action`, `size`, `exitPrice`, `entryPrice`, `realizedPnl`, `netRealizedPnl`, `realizedRoe`, `closedAt`) and `nextPageToken`.
</ResponseField>

<ResponseField name="listLeadTraderOpenPositions" type="(handle: string) => Promise<ListLeadTraderOpenPositionsResponse>">
  The open positions of a leader you currently follow (`tradingPairId`, `side`, `size`, `entryPrice`, `markPrice`, `unrealizedPnl`, `leverage`, `marginMode`). Requires authentication; 403 unless you follow that leader.
</ResponseField>

<ResponseField name="upsertFollow" type="(params: UpsertFollowParams) => Promise<UpsertFollowResponse>">
  Follow a leader (no `followId`) or edit one of your follows (`followId` set). A create moves `allocation` from your margin account into a new copy account: a cross risk bucket that holds this follow's collateral and positions. Requires authentication; delegated agent and sub-account sessions get 403. A create and an edit each spend the per-account [settings-write budget](/developers/rate-limits#settings-and-copy-trading-writes) (about one write per second, burst 10) that `upsertLeadTrader` and the self-trade-prevention default share; 429 with `retryAfter` past it.

  **Params:**

  * `followId?`: string (UUID) — set to edit
  * `leader?`: string — the leader's handle; required on a create, optional on an edit
  * `allocation`: string — collateral for the copy account, in quote units
  * `marginModePolicy?`: `"FOLLOW"` (default) | `"CROSS"` | `"ISOLATED"`
  * `sizingMode?`: `"PROPORTIONAL"` (default) | `"FIXED_MARGIN"`
  * `sizingParam?`: string — margin per leader order; required with `FIXED_MARGIN`, rejected otherwise
  * `leverageMode?`: `"FOLLOW"` (default) | `"FIXED"`
  * `fixedLeverage?`: string — required with `FIXED`, rejected otherwise
  * `slPct?`: string — copy stop-loss as a fraction of the allocation, in `(0, 1]`
  * `tradingPairIds?`: string\[] — markets to copy; omit for every market the leader trades
  * `copyExisting?`: boolean — on a create, also copy the leader's currently open positions (see `previewFollow`); refused on an edit

  **Returns:** `followId`, `copyRiskBucketId`, `created`.

  <Warning>
    An edit **replaces** the follow's settings. Every optional setting you leave out reverts to its default, so an edit that omits `slPct` removes the stop-loss. Send the full configuration on every edit.
  </Warning>
</ResponseField>

<ResponseField name="stopFollow" type="(followId: string) => Promise<StopFollowResponse>">
  Stop one of your follows: the leader's fills stop being mirrored. Never refused for the state of the account or the platform. Only three things apply: ownership, the refusal of a delegated agent session, and a per-account rate limit of its own (about one stop per second, burst 20) that closes and edits never spend; 429 with `retryAfter` past it. Returns `followId`.
</ResponseField>

<ResponseField name="closeFollowPositions" type="(followId: string) => Promise<CloseFollowPositionsResponse>">
  Close every position in one of your follows' copy accounts at market (reduce-only, immediate-or-cancel) and cancel the resting orders and conditional orders (TP/SL) on its copy risk buckets, **keeping the follow**: the leader's next trades keep mirroring. Proceeds stay in the copy account. **Not a flatten guarantee**: a thin or halted market can leave part of a position open, and the leader's next trade opens copies again; stop the follow to end the copying. Never gated by copy trading being off or an operations block, no order budget; only a delegated agent session gets 403. Both close methods share a per-account rate limit (about one close per second, burst 5; 429 with `Retry-After`). Returns `{ followId, closeOrdersPlaced, positionsNotClosed }` once the batch is durably logged; each close's fills arrive on the order, position and copy channels. 404 for a follow that is not yours; 409 for a stopped follow or one whose stop is in progress; 400 when the close was refused; 503 when it cannot run right now.
</ResponseField>

<ResponseField name="closeAllCopyPositions" type="() => Promise<CloseAllCopyPositionsResponse>">
  `closeFollowPositions` for every live follow of yours, one batch per follow, keeping the follows. Returns `{ follows, stoppingFollowIds, failedFollows }`: one acknowledgement per live follow whose stop is not in progress (including one with nothing to close), the follows whose stop is in progress (left to their stop), and the follows whose close could not run (`{ followId, reason }`, a fixed sentence; retry them). The others still close.
</ResponseField>

<ResponseField name="addFollowPositionMargin" type="(params: AddFollowPositionMarginParams) => Promise<AddFollowPositionMarginResponse>">
  Add margin to one of your copy positions: moves `amount` from the follow's copy account into the margin of its isolated copy position on `tradingPairId`. The position's initial margin requirement rises by exactly `amount` at the current mark (its leverage drops to what that amount buys at this price), the copy account's remaining collateral falls by the same, and your margin account is never touched. It lowers the position's leverage and moves its liquidation price away; it opens no exposure, so it works while copy trading is switched off and on a `CLOSE_ONLY` follow. `POST /api/v1/copy-trading/follows/{followId}/position-margin`; the follow id is sent in the path and only `tradingPairId` and `amount` in the body.

  **Params:**

  * `followId`: string (UUID) — the follow
  * `tradingPairId`: string (UUID) — trading pair of the copy position
  * `amount`: string — margin to add, in quote units (a positive decimal), taken from the copy account

  **Returns:** `followId`, `tradingPairId`, `riskBucketId` (the copy position's isolated risk bucket), `positionId`, `positionMargin` (the position's stored margin after the add, at the entry price: it rises by `amount × entry price ÷ mark`) and `copyAccountAvailable` (what the copy account can still put into this position after the add), all strings.

  There is no margin reduction: a follow exits by being stopped. Requires a master account session: delegated agent and sub-account sessions get 403. 404 for a follow that is not yours; 409 while the follow is stopping or once it is stopped; 400 with code `COPY_TRADING_REJECTED` when the add is refused (no isolated copy position on the pair, the copy position is being liquidated or is in bad debt, or more than the copy account can put in; the message names the rule); 429 over the movement budget withdrawals and collateral transfers share; 503 when the matching engine is unavailable. Not idempotent: after a timeout, read the follow before retrying, or the amount may be added twice.
</ResponseField>

<ResponseField name="listMyFollows" type="(params?: { pageSize?: number; pageToken?: string }) => Promise<ListMyFollowsResponse>">
  Your follows, newest first. `pageSize` is 1 to 1000.

  **Returns:** `follows[]` and `nextPageToken`. Each `Follow` carries `followId`, `leader`, `status` (`ACTIVE`, `CLOSE_ONLY` or `STOPPED`), the sizing, leverage and margin mode settings, `allocation`, `slPct`, `copyExisting`, `tradingPairIds`, `consecutiveSkips`, `copyRiskBucketId`, `startedAt`, `stoppedAt` and `stopReason`.
</ResponseField>

<ResponseField name="getFollow" type="(followId: string) => Promise<GetFollowResponse>">
  One of your follows with its most recent skipped mirrors: `{ follow, recentSkips, copyAccountEquity? }`, up to 100 skips, each `{ tradingPairId, reason, requestedQuantity, skippedAt }`. `copyAccountEquity` is the copy account's equity at the engine's marks (collateral plus unrealized PnL of its positions), a balance and not trading PnL, absent when the engine cannot be read. 404 for a follow that is not yours.
</ResponseField>

<ResponseField name="previewFollow" type="(params: PreviewFollowParams) => Promise<PreviewFollowResponse>">
  What a follow with these terms would open if it set `copyExisting`, as totals only: `{ estimatedMargin, estimatedFee, copiedPositions, skippedPositions, truncated }`. `estimatedMargin` is the collateral the copies would reserve at placement and `estimatedFee` their taker fees, both in quote units rounded up to cents; the counts say how many of the leader's positions in the copied markets would and would not be copied. The preview names no market, side or reason. At most 64 positions are sized; `truncated` is `true` when the leader holds more. Takes `upsertFollow`'s terms minus `followId`, `slPct` and `copyExisting`, with `leader` required. Read-only. It refuses terms a follow would refuse (400), is refused while copy trading is off (409), and spends the order-risk preview budget (429 when enforced). Requires authentication; delegated agent and sub-account sessions get 403, and an unknown or suspended leader is 404.
</ResponseField>

<ResponseField name="listFollowLeaderPositions" type="(followId: string) => Promise<ListFollowLeaderPositionsResponse>">
  The open positions of the leader one of your follows copies, in the same shape as `listLeadTraderOpenPositions`. The leader comes from the follow, so this works after the leader releases their handle. 404 for a follow that is not yours; 403 for a stopped follow.
</ResponseField>

<ResponseField name="upsertLeadTrader" type="(params?: UpsertLeadTraderParams) => Promise<UpsertLeadTraderResponse>">
  Register as a lead trader, or edit your profile. A registration is checked against the platform's eligibility rules (account equity, trading history, closed positions, a claimed custom TraderCode handle), and a refusal is a 400 naming the rule. Each call spends the per-account [settings-write budget](/developers/rate-limits#settings-and-copy-trading-writes) that `upsertFollow` shares; 429 with `retryAfter` past it.

  **Params:**

  * `shareBps?`: number — your share of followers' realized profit, 0 to 10000; omitted keeps the current share
  * `bio?`: string — at most 2,000 bytes; omitted clears it
  * `status?`: `"ACTIVE"` (default) | `"PAUSED"`
  * `minAllocation?`: string — minimum follow allocation in quote units; omitted clears it

  **Returns:** `created`, `status`, `shareBps`.
</ResponseField>

<ResponseField name="getMyLeadTrader" type="() => Promise<GetLeadTraderResponse>">
  Your own lead profile, follow summary and stats. 404 when you are not a lead trader.
</ResponseField>

<ResponseField name="listMyFollowers" type="(params?: { pageSize?: number; pageToken?: string }) => Promise<ListMyFollowersResponse>">
  Your followers, as a leader: `followers[]` (`walletAddress`, `display`, `status`, `allocation`, `startedAt`) and `nextPageToken`. `pageSize` is 1 to 1000.
</ResponseField>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.