Backtesting Solana DEX Trades with Yellowstone gRPC
Step-by-step guide to replaying historical Solana slot data via the Yellowstone gRPC stream to drive a high-fidelity DEX backtest without synthetic fills. Covers order-book reconstruction, fee modelling, and common look-ahead pitfalls.
Most Solana backtesters are lying to you. They pull OHLCV candles from a CEX proxy, assume mid-price fills, ignore priority fees, and call it a day. If your live bot runs on Raydium or Orca, that methodology will overstate returns by 30–80% on anything shorter than a one-hour hold. Backtesting Solana DEX trades with Yellowstone gRPC eliminates the fiction by replaying the exact transaction stream your bot would have seen in production.
What Yellowstone Actually Gives You
Yellowstone is Triton One's (and compatible providers') gRPC plugin for Solana validators. Unlike standard RPC polling, it delivers a server-push stream of slot updates, account diffs, and transaction notifications with sub-millisecond fan-out from the validator. For backtesting, the relevant subscription filters are:
TransactionSubscribe— every confirmed transaction touching your target programs (e.g., Raydium CPMM, Orca Whirlpools, Meteora DLMM)AccountSubscribe— pool reserve account diffs, so you can track exact liquidity at each slot boundarySlotSubscribe— slot sequence numbers and their confirmed/finalized status, which is your replay clock
Critically, the stream preserves transaction ordering within a slot — specifically the index field in the transaction metadata. This is the only correct way to reconstruct what the on-chain state was before your hypothetical trade landed versus after other transactions in the same slot.
Building the Replay Engine
The replay pipeline has three stages: ingestion, state reconstruction, and strategy evaluation.
Ingestion: Archive the raw gRPC stream to object storage (S3/R2) as slot-ordered protobuf files. Use Yellowstone's CommitmentLevel::Confirmed during collection; Processed gives you more data but introduces forks you'll have to reconcile. A single busy Raydium pool generates roughly 2–4 GB of compressed transaction data per day, so budget your storage accordingly.
State reconstruction: For AMM pools, parse the reserve accounts from AccountSubscribe diffs. For each slot N, the pre-transaction reserve is the state from slot N-1's final account update. Apply transactions in index order to arrive at each intermediate state. The constant-product formula x * y = k gives you the exact execution price for any hypothetical swap size at each point in the slot.
Strategy evaluation: Feed each reconstructed state into your strategy logic as if it were live. The key discipline here is enforcing a strict information barrier: your strategy at slot N may only consume data from slots < N. A single accidental lookahead — using a moving average computed over a window that includes slot N to decide whether to trade at slot N — will produce results that are completely unachievable in production.
Fee Modelling That Actually Reflects Live Conditions
AMM fees are only part of the cost. A realistic fee model for a Solana DEX backtest must include:
- Protocol swap fee — 0.25% on most Raydium CPMM pools, 0.3% on standard Orca, configurable per-tick on Meteora DLMM
- Priority fee — model this as the 75th-percentile compute-unit price observed in the same slot for competing transactions. In busy periods this regularly hits 0.01–0.05 SOL per transaction
- Jito tip — if your live bot uses bundles, add the tip. For backrunning strategies this is often the dominant cost, not the protocol fee
- Slippage — your simulated swap must traverse the actual reserve curve, not use a mid-price approximation. For trades larger than 0.1% of pool liquidity, the difference is material
A useful sanity check: replay 48 hours of a well-understood pool, compute the theoretical arbitrage PnL assuming perfect signal, then verify it broadly matches what you observe on-chain from known arbitrage bots during that period. If your model shows 3× what the arbitrageurs extracted, something is wrong with your fee or fill model.
Look-Ahead Pitfalls That Kill Real Strategies
The two most common look-ahead bugs in Solana backtests are lagged feed construction and settlement timing errors.
With lagged feeds: if you compute any feature — TWAP, volume, recent trade direction — by reading from a database that was populated asynchronously, verify that the database write timestamp for slot N data is strictly earlier than the slot N evaluation timestamp. An async writer that batches commits can easily let slot N+5 data pollute your slot N feature vector.
With settlement timing: Solana finalizes slots roughly 32 slots (~12–13 seconds) after confirmation. If your strategy exits based on a "finalized" price but enters on "confirmed", you've created an asymmetric information edge that doesn't exist in production. Pick one commitment level and use it consistently for both entry and exit logic.
A third subtler issue is pool selection bias: if you choose which pools to backtest based on knowing they had high volume or interesting price action over the period, you've already introduced look-ahead. Pool selection must be defined by criteria that could have been applied at the start of the period using only prior data.
Connecting Backtest Results to Live Infrastructure
A backtest that doesn't connect to your live execution path is a research toy. The way to bridge this gap is to write your strategy logic as a pure function that takes the reconstructed slot state as input and returns an order intent — and then use the same function, unmodified, in your live Solana MEV and arbitrage bot or market-making bot. The live execution layer wraps it with Jito bundle submission and priority-fee calibration; the backtest wraps it with the replay engine. If you've built the interface correctly, the only difference between backtest and live is what feeds the state.
Validating the bridge is straightforward: run your strategy in shadow mode — same code path, live state feed, no real submissions — and compare shadow fills against the replay fill model on the same time window. Systematic discrepancies point to modelling gaps, not alpha decay.
This approach is exactly what we apply when building production Solana trading bots and infrastructure here at TierZero. A strategy that hasn't been validated against real slot data, with real fee models and real ordering constraints, hasn't been validated at all.
If you want help building a Yellowstone-backed backtest harness or wiring it into a live execution engine, reach out — we scope and price these engagements quickly.
Need a bot like this built?
We design, build and run trading bots on Solana, Hyperliquid and Polymarket.
Start a projectMore from the blog
Public vs Paid RPC: How to Run a Fair Benchmark
A fair comparison of public and paid RPC endpoints must account for quotas, workload, freshness and support guarantees.
Read articleRPC Benchmark Percentiles Explained: p50, p95 and p99
Why averages hide the latency spikes that break trading bots, wallets and production blockchain applications.
Read articleHyperliquid REST vs WebSocket Benchmark: What to Measure
A benchmark plan for Hyperliquid market data that separates request latency from streaming freshness and recovery.
Read article