Four numbers run my pump.fun bot:
dev buy >= 1 SOL take +30% stop -30% hold 120s
Enter fullscreen mode Exit fullscreen mode
On one real hour of pump.fun data, that setup took 1,034 trades and finished +40.2 SOL. Every buy and sell was priced through the real bonding curve, with all fees paid on both sides.
I did not invent those numbers. I tested 270 combinations and read the results. What matters is why they win, and it comes down to one calculation that almost nobody runs before switching a bot on.
First, work out what a trade costs you
A pump.fun token is a pool with two sides: SOL on one side, tokens on the other. When you buy, SOL goes in and tokens come out, and the price of the next token goes up. When you sell, it goes back down. This is the bonding curve.
Two things follow from that, and they cost you money.
You pay more than the quoted price when you buy, because your own order pushes the price up while it fills. You get less than the quoted price when you sell, for the same reason in reverse. On top of that, pump.fun takes a 1.25% pool fee each way.
Every event in the data tells you exactly how much is in the pool, so you can calculate a real fill instead of guessing:
-
vQuoteInBondingCurveis how much SOL is in the pool -
vTokensInBondingCurveis how many tokens are in the pool
Here is a buy and a sell, priced properly:
POOL_FEE = 0.0125 # pump.fun takes 1.25% each way
def tokens_i_get(sol_in_pool, tokens_in_pool, sol_i_spend):
"""How many tokens I actually receive for my SOL."""
after_fee = sol_i_spend * (1 - POOL_FEE)
k = sol_in_pool * tokens_in_pool # the pool keeps this constant
return tokens_in_pool - k / (sol_in_pool + after_fee)
def sol_i_get(sol_in_pool, tokens_in_pool, tokens_i_sell):
"""How much SOL I actually receive for my tokens."""
k = sol_in_pool * tokens_in_pool
before_fee = sol_in_pool - k / (tokens_in_pool + tokens_i_sell)
return before_fee * (1 - POOL_FEE)
Enter fullscreen mode Exit fullscreen mode
Now buy 0.5 SOL of a token and sell it back one second later. Nothing happened in between. No price move, no other traders.
break-even move needed: 2.55%
Enter fullscreen mode Exit fullscreen mode
You are 2.55% down the moment you enter. Same at every pool size. That is the toll, and your take-profit has to clear it before a single lamport of profit exists.
Which explains a lot. A bot that takes 3% is really trading for 0.45%. A bot that takes 5% keeps about half of what it earned. That is why the high win-rate snipers everyone builds bleed slowly: they are right most of the time and pay 2.55% on every round trip.
So I stopped looking at small targets and went hunting for moves big enough that the toll becomes a rounding error.
Two and a half million events, one URL
The data is free and needs no signup. Historical replay saves one file per hour:
https://replay.pumpapi.io/2026/07/30/15.jsonl.zst
Enter fullscreen mode Exit fullscreen mode
Each line is one JSON event, the same shape the live pump.fun data stream sends over websocket. One parser works for both your backtest and your live bot.
import io, datetime
import requests, zstandard as zstd
import orjson as json
hour = datetime.datetime(2026, 7, 30, 15, tzinfo=datetime.timezone.utc)
url = f"https://replay.pumpapi.io/{hour:%Y/%m/%d/%H}.jsonl.zst"
with requests.get(url, stream=True, timeout=900) as r:
r.raise_for_status()
with zstd.ZstdDecompressor().stream_reader(r.raw) as reader:
for line in io.TextIOWrapper(io.BufferedReader(reader, 1 << 20), encoding="utf-8"):
if line.strip():
event = json.loads(line)
# event["action"] is "create", "buy", "sell", "transfer", ...
Enter fullscreen mode Exit fullscreen mode
That single hour holds 2,551,714 events and 2,042 new pump.fun tokens.
The signal, and the filter I nearly got wrong
The signal is the token creator, usually called the dev. A dev who creates a token and buys into it pays the pool fee going in and going out. Put in 50 SOL and you are more than a SOL down before the chart moves. Nobody does that planning to lose, so he needs the price up, and soon. You ride behind him.
My first instinct was to only follow the big ones. Then I counted how often big ones happen:
dev's own opening buy (SOL): median 1.00 max 736.42
>= 1 SOL: 1,036 launches
>= 3 SOL: 648
>= 5 SOL: 248
>= 10 SOL: 66
>= 20 SOL: 25
>= 50 SOL: 17
Enter fullscreen mode Exit fullscreen mode
Seventeen an hour clear 50 SOL. Filter that hard and your bot sits idle all day. The median dev puts in 1 SOL, and that is where the money turned out to be: 1,034 trades an hour instead of 25.
270 setups, one table
Once the history is on disk, testing another idea costs nothing. So I recorded the pool size at every moment of every launch, then ran 270 simulations over it: dev buy at 1, 3, 5, 10, 20 SOL, targets from 5% to 200%, stops at 15, 30, 50%, holds at 120, 300, 900 seconds. Every fill priced through the curve with both fees applied.
| dev buy | take profit | stop loss | hold | trades | win % | net SOL |
|---|---|---|---|---|---|---|
| 1 SOL | +30% | -30% | 120s | 1,034 | 52.7% | +40.26 |
| 1 SOL | +30% | -30% | 300s | 1,034 | 52.3% | +39.51 |
| 1 SOL | +30% | -50% | 120s | 1,034 | 53.7% | +39.42 |
| 1 SOL | +50% | -15% | 120s | 1,034 | 37.2% | +38.90 |
| 1 SOL | +30% | -15% | 120s | 1,034 | 49.3% | +38.11 |
| 3 SOL | +200% | -50% | 300s | 646 | 14.1% | -10.97 |
Three things came out of that table.
+30% is the sweet spot, and it is not arbitrary. It is about twelve times the 2.55% toll. Far enough away that the curve stops deciding the outcome, close enough that half the launches actually reach it.
Greed loses. Wait for +200% and you win 14% of the time and finish 11 SOL down. Those runners are real, just not frequent enough to pay for 555 losers.
Speed beats patience. A 120 second hold wins in every row. If a launch has not moved 30% in two minutes, waiting does not help. Take the loss, free the slot, the next launch is already arriving.
A 52.7% win rate is barely better than a coin flip. Run it 1,034 times an hour, with winners the same size as losers and a toll too small to matter, and that is the entire edge.
Placing the trade
A strategy still needs something to execute it, and this is where most pump.fun bot projects die. People spend six weeks building transactions by hand, get bored, and never trade.
I POST to a pump.fun API and let it build, sign and send the transaction:
import requests
API = "https://api.pumpapi.io"
def buy(mint, sol, api_key):
return requests.post(API, json={
"apiKey": api_key,
"action": "buy",
"mint": mint,
"amount": sol, # how much SOL to spend
"denominatedInQuote": True,
"slippage": 20, # percent
"priorityFee": 0.00005,
}, timeout=10).json()
def sell_everything(mint, api_key):
return requests.post(API, json={
"apiKey": api_key,
"action": "sell",
"mint": mint,
"amount": "100%", # dump the whole bag
"denominatedInQuote": False,
"slippage": 20,
"priorityFee": 0.00005,
}, timeout=10).json()
Enter fullscreen mode Exit fullscreen mode
Two functions, and that is the whole execution layer.
slippage: 20 is the curve again, not paranoia. On a fresh launch the pool moves between your decision and your transaction landing. Set 1% and you will watch good entries fail while slower bots fill.
The apiKey is there because I keep no private key in my bot's source. One call gives you an encrypted stand-in to pass instead:
res = requests.post("https://wallet.pumpapi.io", json={}).json()
# {"apiKey": "...", "publicKey": "...", "privateKey": "..."}
Enter fullscreen mode Exit fullscreen mode
An empty body creates a brand new wallet. The apiKey goes in the bot config and the privateKey goes nowhere near it. Trade from a dedicated wallet holding only money you can lose, and never paste your main wallet's key into a bot, a config file, or an AI chat.
If handing over any kind of key bothers you, the same API has a local mode: it returns the unsigned transaction, and you sign and send it through your own RPC. Slower, but the key never leaves your machine. I use the managed path because this race is decided in milliseconds.
From the table to the bank
+40 SOL an hour on paper is not +40 SOL an hour in your wallet, and anyone who says otherwise is selling a course.
The simulation has no latency. It sees a new launch the instant it exists, while your bot sees it after the network, the parsing and the decision, with other snipers in the same race. One hour is a demo, not a study. And I picked the winner off a 270-row table, so some of that +40 is luck in a nice suit.
What I actually did:
Re-ran the sweep over days instead of one hour. Checked those four numbers again on a period I never tuned on. Went live at 0.05 SOL per trade, small enough that being wrong costs nothing. Compared real fills against the simulation for a week. Increased size only while the two kept agreeing.
That last step is the job. It is what turns a table into roughly $4,000 on a good day and much less on a quiet one, because this bot sells volatility and pump.fun does not hand it out evenly.
Take these three things
Work out your round-trip cost from the pool before you write any trading logic. On a 0.5 SOL position it is 2.55%, and it quietly eats every small target you will ever design.
Win rate means nothing on its own. 52.7% made 40 SOL. An earlier setup of mine won 74% of its trades and still finished down, because the winners were smaller than the toll.
Use the same event format for backtest and live, or you are testing a bot you will never run.
The replay files are free, which is the only reason I ran the sweep that found these numbers. You pay when you trade.
I have a second bot doing closer to $5,000 a day. Same replay files, different signal out of the same events, found the same way. If people want it, I will write that one up with the exact fields it filters on.
What is the first idea you would throw at 2.5 million events an hour?
0 Comments
Log in to join the conversation.No comments yet. Be the first to share your thoughts.