> ## 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.stopFollow(followId);

// 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.

  **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 gated beyond ownership, except that a delegated agent session cannot stop a follow. Returns `followId`.
</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.

  **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>
