How to download historical pump.fun data with Python
Every backtest starts the same way: you need the raw history. This guide walks through downloading tick-level pump.fun trades and 1-second OHLCV candles with Python and the Raiden pump.fun API — six months of history, every fill on both the bonding curve and PumpSwap (pAMM), with keyset pagination for bulk export.
What you need
- A Raiden API key (private beta — free, invite-only). Every
request sends it in the
X-API-Keyheader. - Python 3.10+ with
requestsandpandas.
1 · Pick your tokens
The screener endpoint lists tokens with keyset pagination. Grab the freshest launches, or filter by status to only get graduated tokens:
import requests BASE = "https://terminal.raiden.wtf/api" H = {"X-API-Key": "YOUR_KEY"} tokens = requests.get(f"{BASE}/tokens", params={"sort": "newest", "limit": 100}, headers=H).json() mints = [t["mint"] for t in tokens["data"]]
2 · Download every trade of a token
/tokens/{mint}/swaps returns individual fills — price, SOL and token
amounts, every fee component, tip, priority fee, slot and block index. Large numbers
come back as strings in lamports (1 SOL = 10⁹ lamports) to avoid float loss.
Paginate with order + cursor (a boundary timestamp):
def all_swaps(mint): rows, cursor = [], None while True: p = {"order": "asc", "limit": 200} if cursor: p["cursor"] = cursor page = requests.get(f"{BASE}/tokens/{mint}/swaps", params=p, headers=H).json() rows += page["data"] if not page.get("next_cursor"): break cursor = page["next_cursor"] return rows swaps = all_swaps(mints[0]) # each row: time, trader, is_buy, sol_amount, token_amount, price, # fee, creator_fee, priority_fee, tip, slot, block_index, sig, venue …
Add failed=1 to interleave reverted trade attempts (rows carry
"failed": true) — the lost bids most data sources drop, useful to measure
real demand during a snipe war.
3 · Or grab candles down to 1-second resolution
For most backtests OHLCV is enough — and far fewer rows. tf accepts
1s, 30s, 1m, 1h, 1d,
with from/to bounds (RFC3339):
candles = requests.get(f"{BASE}/tokens/{mint}/candles", params={"tf": "1s", "from": "2026-07-01T00:00:00Z", "to": "2026-07-02T00:00:00Z"}, headers=H).json()["data"] # [{"time": "...", "open": "...", "high": "...", "low": "...", # "close": "...", "volume": "...", "trades": 137}, ...]
4 · Into pandas
import pandas as pd df = pd.DataFrame(swaps) df["time"] = pd.to_datetime(df["time"]) for col in ("sol_amount", "price", "fee", "tip"): df[col] = pd.to_numeric(df[col]) df["sol"] = df["sol_amount"] / 1e9 # lamports → SOL buys = df[df.is_buy].resample("1min", on="time").sol.sum()
Tips for bulk export
- Use
order=asc+ cursor for full-history walks — each page is an indexed seek, so deep pagination stays fast. - Respect your key's rate limit — it is sized per use case and raised on request during the beta.
- One call instead of nine:
/tokens/{mint}/packreturns the full token dossier (launch, holder stats, smart money, trust score, wash traders) in a single response — ideal for enriching a dataset. - Venue matters: each swap carries its venue (bonding curve or PumpSwap), so a token's history is continuous through graduation.
Full request/response shapes for every endpoint are in the API reference. Next up: track pump.fun wallets and their PnL or stream trades in real time over WebSocket — or jump straight to backtesting on 1-second candles, the other half of this pipeline.
Frequently asked questions
How much pump.fun history does the API keep?
Six months of tick-level swaps and 1-second candles — full history since the index launched on May 1, 2026. Token metadata, creators and wallet PnL are kept for the life of the index.
Why are amounts returned as strings?
Amounts are lamports (1 SOL = 10^9 lamports) serialized as strings to avoid floating-point precision loss on large values. Convert with pandas.to_numeric or Python int() before doing math.
Can I export data for many tokens at once?
Yes — walk the screener with keyset pagination to enumerate mints, then fetch swaps or candles per mint. Batch-friendly: every list endpoint returns a next_cursor you pass back until it is empty.