← Back to Blog

trading

I Built a Solana Sniper Bot in Python — Here's the Real P&L (Losses Included)

I Built a Solana Sniper Bot in Python — Here's the Real P&L (Losses Included)

I'll give you the number first, because every other build log buries it: the wallet is down about 0.48 SOL, and the machine-learning model that scored a gorgeous 0.78 AUC in testing went 4 wins and 83 losses once it was gating real trades. If you're about to build a pump.fun sniper, that one sentence is worth more than another "10x overnight" thread. Not financial advice — most memecoins go to zero, and a sniper bot mostly just finds that out faster.

This is the whole story: what I built, the bug that ate three-quarters of my trades, and the morning the data quietly told me the edge wasn't there.

Sixty seconds is the entire game

On pump.fun, every token launches onto a bonding curve — a fixed formula where the price climbs as people buy and falls as they sell, until enough SOL pools up that the token "graduates" to a real exchange. Sniping means catching a launch within seconds, buying low on the curve, and selling into the crowd that piles in behind you. If an edge exists anywhere in this, it lives in the first 30–60 seconds. Every engineering decision below is downstream of that clock.

Three processes that can't take each other down

I deliberately split the bot into independent systemd services so a single stall couldn't freeze the whole thing mid-trade:

It's plain Python throughout — httpx for async RPC, solders/base58 for keys and signing, Helius for RPC and WebSocket, Jupiter for routing. None of that is the hard part. The hard part is always the milliseconds and the edge cases.

The bug that quietly killed 74% of my buys

This is the kind of thing tutorials never mention. For a while, roughly three of every four buys failed with a Token-2022 "Invalid Mint" error (0x2) — on tokens that had obviously just minted seconds earlier.

The culprit: Solana's sendTransaction runs a preflight simulation, and by default it simulates against the finalized commitment level, which trails the chain tip by 13–30 seconds. When you're buying a token that is seconds old, the simulating node hasn't even seen the mint account yet, so it rejects your transaction with a misleading program error. The entire fix is one line:

# simulate against the chain tip, not finalized state
opts = {"preflightCommitment": "processed"}

If you take one practical thing from this post, take that. Fresh-account transactions on Solana fail in baffling ways until you set preflightCommitment: "processed".

Teaching a model to pick winners

The interesting question was never "can you buy fast." It was "can you tell, at the moment of entry, which launches are worth buying." So I trained a series of XGBoost classifiers on historical launches, each adding features available at decision time:

One data lesson nearly broke the whole feature set: you cannot classify those early trades by who paid the fee. Sniper bots routinely pay fees from one wallet while the tokens land in another, so a naive "who paid" approach reports zero buyers on heavily-traded mints. The correct method is to diff token-balance changes against the bonding-curve program address — any account whose balance went up is a buyer, and the curve's own lamport change is the true SOL size. Tiny detail, completely different features.

On paper this looked like a model that was genuinely learning. AUC climbing 0.61 → 0.78 reads like progress.

The morning the backtest stopped mattering

Then I ran a guarded live canary — small fixed size, a hard daily loss cap, chain-enforced slippage limits — and let the model gate real entries. Over 87 trades it went 4 wins, 83 losses, down 0.139 SOL. And the detail that actually mattered: when I bucketed those trades by model score, the win rate was flat across every bucket. The high-confidence entries did no better than the low-confidence ones. A beautiful 0.78 AUC translated into exactly nothing live.

The honest reasons it falls apart:

So what was it actually worth?

Here's where I landed, and it isn't a checklist. The most valuable thing this bot produced wasn't profit — it was a clean dataset of decision-time features joined to real outcomes, which is the only thing that lets you prove whether an edge exists instead of hoping one does. The score model turned out to be the wrong lever entirely: when entries have no edge, tuning the classifier is rearranging deck chairs, and exit structure, sizing, and hard filters (like blacklisting serial relaunch developers) matter far more than another 0.05 of AUC.

So right now the bot is paused. The infrastructure still runs in shadow mode, logging every decision so I can keep asking the only question that matters — does any version separate live winners from losers — and answer it with data instead of optimism. If a future model clears that bar, I'll wire it back up. If it never does, that's an answer too, and a cheaper one than most people pay to learn it.

That's the point of doing this in the open. The losses are the data.


A transparency log of a real engineering and trading experiment — not financial advice, and not a service you can buy. Memecoin sniping sits a short walk from gambling; I treat these losses as tuition for building in public. Never put in money you can't afford to lose.