Build a pump.fun copy trading bot with WebSocket streams
A copy trading bot has two halves. The execution half — keys, signing, submission, landing — is yours and is not covered here. The data half — knowing that a wallet worth copying just bought, in sub-second, with enough context to decide whether to follow — is what this guide builds, end to end, on the Raiden API. Raiden supplies the eyes of a pump.fun copy trading bot; you bring the hands. Getting the eyes right is where most solana copy trading bot projects quietly fail: they detect too slowly, mirror blindly, and never handle the exit.
The architecture in one screen
| # | Layer | What it does | API surface |
|---|---|---|---|
| 1 | Leader list | The wallets worth mirroring, saved server-side | POST /wallet-groups + …/wallets |
| 2 | Stream | A subscription that pushes only those wallets' fills | POST /ws-subscriptions |
| 3 | Listener | The WebSocket connection consuming type: swap events | wss://terminal.raiden.wtf/ws |
| 4 | Risk gate | Pre-trade checks on every signal before mirroring | /tokens/{mint}/trust, /tokens/{mint}/swaps |
| 5 | Exit mirror | The leader's sell is a swap event too — act on it | same stream |
Step 1 — Curate the leaders into a wallet group
A copy bot is only as good as the wallets it copies. How to find and vet them — realized PnL net of all fees, win rate, hold style, and the traps in each metric — is its own guide: the best Solana wallets to copy trade. Vetting runs on a 6-month rolling window of history (complete record since May 1, 2026), so a leader's track record is checkable before you wire money to its signals. Once you have the shortlist, save it as a wallet group — streams filter by group id, never by inline addresses:
curl -X POST -H "X-API-Key: $RAIDEN_KEY" -H "Content-Type: application/json" \ -d '{"name":"Copy leaders"}' "https://terminal.raiden.wtf/api/wallet-groups" { "id": "grp_5f3a…", "name": "Copy leaders", "count": 0, "members": [] } curl -X POST -H "X-API-Key: $RAIDEN_KEY" -H "Content-Type: application/json" \ -d '{"wallets":["8psN…VRtf","Cb3f…g9rE"]}' \ "https://terminal.raiden.wtf/api/wallet-groups/grp_5f3a…/wallets" { "ok": true, "added": 2 }
Adds are idempotent and a group holds up to 1,000 wallets. The stream resolves the
group into a wallet snapshot when it is created or updated — so after editing the
roster later (drop a decaying leader, add a new one), re-issue a PUT on
the stream to re-resolve the list. The sub token stays the same, so the bot itself
never changes.
Step 2 — Create the stream
One call creates a push subscription for the swaps kind, filtered to your
group. The response contains the opaque token you connect with:
curl -X POST -H "X-API-Key: $RAIDEN_KEY" -H "Content-Type: application/json" \ -d '{"name":"copy-leaders","kinds":["swaps"],"wallet_list_id":"grp_5f3a…"}' \ "https://terminal.raiden.wtf/api/ws-subscriptions" { "id": 3, "token": "sub_a1b2c3…", "name": "copy-leaders", "active": true, "kinds": ["swaps"], "wallet_list_id": "grp_5f3a…", "wallets": ["8psN…VRtf", "Cb3f…g9rE"] }
Accounts get 3 streams by default — enough to split leaders by strategy (one stream of scalpers, one of holders) and size the mirror differently per stream. The full stream system — all five kinds, filters, reconnection — is covered in the pump.fun WebSocket guide.
Step 3 — Connect and read swap events
Connect with your API key and the sub token; only events matching the stream's kinds
and filters are pushed. Every fill by a tracked wallet arrives as a
type: swap event:
wscat -c "wss://terminal.raiden.wtf/ws?key=$RAIDEN_KEY&sub=sub_a1b2c3…" { "topic": "sub:3", "type": "swap", "time": "2026-07-13T09:01:22.400Z", "mint": "…pump", "trader": "8psN…VRtf", "is_buy": true, "sol_amount": 4200000000, "token_amount": 191833, "price": "0.0000041", "sig": "…", "slot": 351902144, "tip": 100000 }
token_amount is in raw token base units. REST endpoints
return large numbers as strings; the WebSocket swap event pushes them as numbers, with
price as a string. A sol_amount of 4200000000
is a 4.2 SOL buy.
This event is the entire signal: who (trader), what (mint),
which direction (is_buy), how big (sol_amount), at what
price, in which slot. To copy trade pump.fun wallets you now need the part most
bots get wrong — deciding whether to mirror.
Step 4 — The mirror decision layer
A raw mirror ("leader bought → I buy") is a machine for inheriting other people's exit liquidity. Three checks — each a single API call — separate a bot from a donation:
- Trust gate.
GET /tokens/{mint}/trustreturns a live 0–100 score with a verdict:clean(≥65),caution(40–64),likely_rug(<40). Never mirror a buy intolikely_rug— the leader may be an insider entering a position you cannot exit, or exit-scalping a dump you will hold. The score blends dev reputation, known rug-dumpers currently in the token, bundled supply, dev exit and wash trading; the full methodology is in the pump.fun rug check guide. - Position sizing. Size relative to the leader, never fixed. A leader's 0.2
SOL probe and its 15 SOL conviction entry are different signals; a flat mirror size
treats them identically. A fraction of
sol_amountwith a hard cap keeps your exposure proportional to theirs. - Slippage guard. Between the leader's fill and your decision, the price
moves.
GET /tokens/{mint}/swaps?order=desc&limit=1returns the latest indexed trade — compare itspriceto the event's. If the token already ran well past the leader's entry, you are not copying a trade, you are chasing one.
curl -H "X-API-Key: $RAIDEN_KEY" "https://terminal.raiden.wtf/api/tokens/…pump/trust" { "mint": "…pump", "score": 45, "verdict": "caution", "capped": true, "cap_reason": "bundled", "signals": { "dev_score": { "value": 0, "comp": 8.4, "known": true }, "dumpers_holding": { "value": 3, "comp": 15.0, "known": true }, "bundled_pct": { "value": 52.0, "comp": 0.0, "known": true }, … } }
Step 5 — Exits: the half most bots skip
The leader's sell is also a swap event — same stream, is_buy: false. A
copy bot that mirrors entries but not exits is long everything its leaders have
already left; mirroring the exit is three lines in the listener below. One caveat
decides whether a leader is copyable at all: the fast flip. A sniper that lands
in the same slot as the token creation has entered — and often exited — inside a
window no external signal can beat; with human or API latency you would buy its exit.
Before wiring a leader in, measure it: GET /versus scores 2–5 wallets on
their shared tokens with per-fill slot and block-index timing, and
the wallet-landing guide shows how
to read the result. Leaders whose edge is selection, not landing — entries several
slots after creation, holds measured in minutes — are the ones mirror trading
solana style actually works on.
The full listener in Python
import asyncio, json, requests, websockets BASE = "https://terminal.raiden.wtf/api" KEY = "YOUR_KEY" H = {"X-API-Key": KEY} WS = f"wss://terminal.raiden.wtf/ws?key={KEY}&sub=sub_a1b2c3…" MIRROR_RATIO = 0.10 # copy 10% of the leader's size MAX_LAMPORTS = 500_000_000 # hard cap per entry (0.5 SOL) MAX_CHASE = 0.15 # skip if price already ran >15% past the fill positions = {} # mint -> lamports we hold def risk_gate(ev): """Return a sized buy in lamports, or None to skip.""" mint = ev["mint"] # 1 · trust verdict — never mirror into a likely rug t = requests.get(f"{BASE}/tokens/{mint}/trust", headers=H).json() if t["verdict"] == "likely_rug": return None # 2 · slippage guard — latest indexed price vs the leader's fill last = requests.get(f"{BASE}/tokens/{mint}/swaps", params={"order": "desc", "limit": 1}, headers=H).json()["data"] if last and float(last[0]["price"]) > float(ev["price"]) * (1 + MAX_CHASE): return None # already ran away — chasing, not copying # 3 · size relative to the leader, capped return min(int(ev["sol_amount"] * MIRROR_RATIO), MAX_LAMPORTS) def execute_buy(mint, lamports): # === YOUR STACK: build, sign, submit, confirm === raise NotImplementedError def execute_sell(mint): # === YOUR STACK === raise NotImplementedError async def listen(): async with websockets.connect(WS) as ws: async for raw in ws: ev = json.loads(raw) if ev.get("type") != "swap": continue mint = ev["mint"] if ev["is_buy"]: if mint in positions: continue # already in — don't stack entries size = risk_gate(ev) if size: execute_buy(mint, size) positions[mint] = size elif mint in positions: # the leader's SELL — mirror the exit execute_sell(mint) del positions[mint] asyncio.run(listen())
requests
calls for clarity — move them to an async client so one slow lookup never delays the
next event. Reconnect with backoff, and treat a restart as a state problem: your
positions dict must survive it, or exits will be missed.Why most copy bots lose
- Latency vs the leader. You always enter after them and exit after them — both deltas cost money on every round trip. The bot is only viable on leaders whose profit per trade is much larger than your two deltas; that is a property you select for, not one you engineer around.
- Entries without exits. Mirroring buys and "managing" sells manually means holding every position through the leader's exit dump. The sell signal is already in the stream — not using it is a choice.
- Mirroring insiders. A wallet with a spectacular win rate on tokens that later rug is not skilled — it is early because it is connected. The trust gate catches the token side; vetting the leader's history catches the wallet side.
- Copying the uncopyable. Same-slot snipers look best on every leaderboard and are precisely the wallets whose edge cannot be inherited. Measure first, follow second.
Everything above is public API surface — full request and response shapes are in the API reference, and the free invite-only beta keys described in the pump.fun API overview are enough to build and test the whole data half before a single SOL is at risk.
Frequently asked questions
Does the Raiden API execute my copy trades?
No. Raiden is the data side only: it detects the leader's fill and pushes it to you in sub-second over WebSocket, and gives you the risk data to decide. Signing, submission and execution are your own stack — there is no trading API.
How do I avoid copying a wallet into a rug?
Gate every buy signal through the live trust score: GET /tokens/{mint}/trust returns a 0-100 score and a verdict — clean, caution or likely_rug. Never mirror a buy into a likely_rug token, whatever the leader does; insider entries are often positions you cannot exit.
Can I copy trade a same-slot sniper on pump.fun?
Not profitably. A sniper that lands in the same slot as the token creation has entered — and often exited — before any external signal can reach your bot. Measure a candidate leader's timing with /versus first: if its edge is same-slot landing, pick a slower leader.
Are the leader's sells streamed too?
Yes — every swap event carries is_buy. A leader's sell arrives on the same stream as its buys, so the listener that mirrors entries can mirror exits with three extra lines. Most losing copy bots copy only the entry.
How many wallets can one stream follow?
The swaps kind is filtered by a wallet group, and a group holds up to 1,000 wallets. Accounts get 3 streams by default, so a single account can follow thousands of leaders split across streams.
What does a swap event contain?
The trader, the mint, is_buy, sol_amount in lamports, token_amount in raw token units, the price, the slot, the transaction signature and the tip — enough to size and gate a mirror decision, with the mint ready for a trust lookup before you act.