Solana Data for Backtesting: How to Build a Historical Trading Dataset Without Look-Ahead Bias
Learn how to build a causality-safe Solana trading dataset for backtesting: token universe, trades, liquidity, execution costs, Pump.fun migrations, validation and reproducible Parquet inputs.
A profitable-looking Solana backtest can be wrong for a very simple reason:
It used information that was not available when the simulated trade was supposed to happen.
Historical blockchain data gives you a detailed record of what happened. It does not automatically give you a valid trading dataset. You still need to define the token universe, order events correctly, build features only from past observations, and model what your strategy could actually have executed.
This guide explains how to build Solana data for backtesting that is useful for research rather than merely impressive in a spreadsheet. It is educational material, not investment advice.
Quick answer: what data does a Solana backtest need?
| Backtest component | Minimum historical data |
|---|---|
| Token universe | Creation/launch records, including tokens that later failed |
| Entry signal | Ordered trades, wallet activity, pool/curve state and any other feature inputs |
| Entry price | Historical executable liquidity, not a later chart close |
| Position tracking | Trades, token balances or a clearly defined accounting model |
| Exit signal | Later events only after they become observable |
| Exit price | Historical venue/pool state, fees and a fill rule |
| Lifecycle changes | Migration, pool creation, liquidity changes and venue switches |
| Reproducibility | Dataset version, coverage manifest, schema version and checksums |
The central rule is:
At each decision time, the strategy may use only data that was observable at or before that time.
Why Solana backtesting is harder than downloading candles
Candles are a convenient summary. They are not a complete execution record.
Suppose a token’s one-minute candle says:
open: 0.000010 SOL
high: 0.000040 SOL
low: 0.000009 SOL
close:0.000025 SOLThat does not tell you:
- whether your signal appeared before or after the high;
- whether enough liquidity existed to buy at the quote you chose;
- what fees were paid;
- whether the token was still on a Pump.fun bonding curve or had migrated;
- whether a route split the order across several venues;
- whether the observed price came from a tiny trade;
- whether your own order would have moved the pool price.
For a credible Solana trading backtest, build from ordered on-chain events and the historical state that governed execution.
The six data layers of a Solana trading dataset
1. Universe data: what could the strategy have traded?
The universe must be defined before evaluating the signal.
For a Pump.fun study, a reasonable universe could be:
Every successful Pump.fun token-creation event in a stated time window, including tokens that had no later liquidity, never graduated, or quickly became inactive.
That is better than starting from a current token list or a list of tokens that later became popular. A current list already excludes many historical failures and introduces survivorship bias.
Useful universe fields include:
- mint address;
- creation slot and event time;
- creator/submitting wallet fields;
- launchpad and initial venue;
- metadata reference;
- token-decimal information;
- initial pool or bonding-curve identity.
2. Event data: what happened, and in which order?
Your event table is the backbone of the system. It should retain enough detail to order and audit each action:
- slot;
- transaction signature;
- transaction index, if supplied by the source;
- outer/inner instruction path or index;
- event time/block time;
- program and decoded event/instruction type;
- success or failure state;
- source schema/version.
Timestamps alone are not a complete ordering mechanism. Multiple events can occur in one slot or share the same timestamp. Where precise within-block ordering matters, use the most granular chain lineage available from the source.
3. Market and venue state: what could have executed?
The execution model must match the liquidity mechanism.
| Venue model | State needed for a realistic backtest |
|---|---|
| Pump.fun bonding curve | Virtual/real reserves, amounts, fees and current curve state |
| Constant-product AMM | Token reserves, fee parameters and pool state |
| Concentrated-liquidity AMM | Current price plus tick/range liquidity |
| DLMM | Active bin and relevant bin liquidity/fee state |
| Aggregator route | Candidate venue state plus a feasible routing/latency assumption |
If you only have a last-traded price, call the result a price-observation backtest, not an execution-quality backtest.
4. Wallet and behavioural data: who was participating?
Wallet features can be useful, but they must be constructed from a point-in-time view.
Examples of causal features include:
- unique buyers observed so far;
- buy/sell imbalance through the current event;
- number of prior launches by the creator at that time;
- a wallet’s realized history only up to that time;
- concentration among currently observed holders, if balance snapshots are available;
- rate of trades and volume over trailing windows.
Do not label a wallet as “smart money” using performance measured after the trade you are trying to predict. That is target leakage disguised as a feature.
5. Cost data: what did the trade actually cost?
A return should include all costs that the strategy would have faced:
- protocol trading fees;
- creator fees where relevant;
- network transaction fees;
- priority fees, if your execution assumption includes them;
- price impact/slippage;
- aggregator or routing costs if applicable;
- exit costs;
- holding costs for products where they apply.
Fees can change across protocol versions and venues. Do not hard-code a current fee schedule onto older history without verifying that it applied at the historical event.
6. Outcome data: what happened after the decision?
Outcomes are allowed for evaluating a decision. They must never leak into its feature set.
Typical labels include:
- return after 30 seconds, 5 minutes or 1 hour;
- maximum adverse excursion after entry;
- realized result under a predefined exit rule;
- curve completion/migration within a future horizon;
- liquidity or volume thresholds reached later.
Store labels in a separate table or explicitly partitioned columns to make accidental future joins harder.
The three biases that ruin most crypto backtests
Look-ahead bias
Look-ahead bias occurs when the strategy uses data that existed only after its decision.
Examples:
- using the one-minute candle close when entering at the beginning of that minute;
- selecting a token because it later graduated to PumpSwap;
- using end-of-day holder counts in a launch-time signal;
- building wallet scores from their full future trading record;
- executing at the best price that occurred later in the interval.
The fix is an as-of join. Every feature row must use a source event whose order is less than or equal to the decision event’s order.
Survivorship bias
Survivorship bias occurs when your historical universe includes only the tokens that remained visible, liquid or successful.
For example, backtesting on today’s list of Pump.fun tokens removes many launches that immediately faded. A model trained on survivors will look better than a model that had to choose in the actual historical launch stream.
The fix is to enumerate the universe from historical creation events, then retain every eligible token whether or not it later traded, migrated or remained queryable.
Execution bias
Execution bias occurs when the simulated fill price was not realistically available to the strategy.
Examples:
- buying a large amount at the last traded price;
- ignoring bonding-curve price impact;
- treating a PumpSwap price as available before migration;
- assuming a known future Jupiter route could have been selected instantly;
- ignoring fees, failed sends and latency.
The fix is to document a conservative execution rule and apply it consistently.
Event time is more important than database time
Historical datasets often carry more than one time field:
- on-chain block/event time;
- slot;
- source receipt/ingest time;
- file partition date;
- dataset publication time.
For causal strategy features, use the on-chain event order. Do not use the time at which an indexer happened to receive a row. And do not let a correction published months later appear as if it were observable to the historical strategy at trade time.
An effective decision key might be represented as:
(slot, transaction_index, instruction_path, event_index)The exact fields depend on the data source. The important part is that the ordering is deterministic, documented and consistent across every feature table.
Worked example: backtest a Pump.fun launch signal
Consider this research hypothesis:
Enter a Pump.fun token after it reaches 50 distinct buyers in its first 60 seconds. Exit ten minutes after the token migrates to PumpSwap, or earlier if a risk rule triggers.
This is only an example of a testable rule. It is not a recommendation to trade it.
Step 1: build the launch universe
Start from every successful Pump.fun creation event in the chosen historical window. Do not start from tokens that eventually migrated.
For each mint, retain the creation time and deterministic event order.
Step 2: derive the first-minute buyer feature
For every mint, include only successful buy events that occur at or before the candidate decision event and within 60 seconds after creation. Deduplicate buyers by wallet identity according to a stated policy.
WITH launches AS (
SELECT mint, event_time AS launch_time, event_order AS launch_order
FROM pump_fun_create_event
WHERE success = TRUE
),
buys_in_window AS (
SELECT
t.mint,
t.user,
t.event_time,
t.event_order
FROM pump_fun_trade_event AS t
JOIN launches AS l USING (mint)
WHERE t.is_buy = TRUE
AND t.success = TRUE
AND t.event_time >= l.launch_time
AND t.event_time < l.launch_time + INTERVAL 60 SECOND
AND t.event_order >= l.launch_order
)
SELECT
mint,
COUNT(DISTINCT user) AS unique_buyers_first_minute
FROM buys_in_window
GROUP BY mint;This illustrative query still needs a defined rule for exact ties and same-slot events. In production, it should also be evaluated at each candidate decision event, rather than using a final count that may include buyers after the actual entry trigger.
Step 3: determine the entry event and price
The 50th distinct buyer does not necessarily mean you can buy at the price paid by that buyer. Your entry occurs later in the ordered event sequence and your transaction has its own size, fee and latency assumption.
For a bonding curve, calculate the fill using the reserve state at the simulated submission/arrival event and the position size. Pump.fun’s official documentation describes the curve as a constant-product AMM with virtual reserves and notes that large trades pay worse fills than small ones.
Step 4: follow the venue transition
The token may remain on the curve, complete it, migrate to PumpSwap, or never migrate. Pump.fun states that graduation migrates the liquidity atomically to PumpSwap and that the transition is automatic and irreversible.
Your model must handle all paths:
| Historical path | Backtest treatment |
|---|---|
| Never reaches entry signal | No position |
| Entry signal, then curve trade remains possible | Price/exit against curve state |
| Curve completes and migrates | Map mint to the historical PumpSwap pool |
| No liquidity at a required exit | Apply your predefined no-fill/partial-fill policy |
| Risk rule fires before migration | Execute against the then-current curve state |
Step 5: calculate the return honestly
One explicit formulation is:
net return = exit proceeds
- entry cost
- entry fees
- exit fees
- network/priority fees
- modeled price impactUse exact token/SOL units until the final presentation layer. Do not allow binary floating-point rounding to silently accumulate over large event sets.
What tables do you need for common Solana strategies?
| Strategy type | Required data | Helpful additions |
|---|---|---|
| New-token momentum | Creation + ordered trades + curve/pool state | Wallet features, metadata, liquidity changes |
| DEX mean reversion | Pool swaps + pool state | Tick/bin state, route information, market benchmark |
| Wallet-following | Wallet actions + asset/venue state | Point-in-time wallet history, balances, cluster features |
| Migration strategy | Launches + curve completion/migration + destination pool | Pre/post-migration liquidity and latency assumptions |
| Liquidation or perp strategy | Fills, funding, order book, liquidations | Position state and market-wide liquidity |
| Market-making simulation | Order book or pool state + trade flow | Queue/latency and cancellation assumptions |
Trades without state may be enough to measure historical activity. They are usually not enough to simulate your own execution.
How to structure the data pipeline
Build the workflow in layers so that you can repeat experiments without corrupting the historical record.
immutable source data
→ validated event tables
→ point-in-time state/features
→ strategy decisions
→ executable fill simulation
→ outcomes and metricsImmutable source data
Keep versioned source files or raw chain records unchanged. Record the data provider, selected coverage, schema version and checksums.
Validated event tables
Normalize timestamps, decimals, transaction status and deterministic event ordering. Preserve signatures/instruction lineage for auditability.
Point-in-time feature tables
Generate features from events up to each decision key. Every feature should carry a feature_as_of_order or equivalent guard.
Strategy decisions
Store why and when a strategy would have entered, sized, reduced or exited. Never overwrite this with later information.
Execution simulation
Apply the defined fill/fee/latency model. Store an execution-quality flag when the data is insufficient for a full fill simulation.
Outcomes and metrics
Calculate returns and risk measures after the decision is locked. Segment results by time period, liquidity regime, token cohort and feature availability.
Validation: how to tell if a backtest is credible
Before believing the final Sharpe ratio or win rate, perform these checks.
Data checks
- Are all expected date partitions present?
- Does the universe include tokens that failed or became inactive?
- Are duplicate/replayed events removed with a documented business key?
- Do sampled rows reconcile to chain signatures?
- Are fee and decimal fields populated across protocol versions?
- Are migration records mapped to the correct destination pools?
Causality checks
- Does every feature have an as-of time/order no later than the decision?
- Is the label/outcome table physically or logically separate from the feature build?
- Are current wallet labels excluded from historical features?
- Are candle aggregates closed before they are used?
Execution checks
- Does entry occur after the signal, not on the signal’s own observed fill?
- Do position sizes exceed available curve/pool liquidity?
- Are fees and price impact included?
- Are failed, delayed or partial fills handled explicitly?
- Does the model switch venues only after a recorded migration?
Research checks
- Is the train/test split chronological rather than random?
- Are parameters selected on a validation period, then frozen for out-of-sample testing?
- Does performance remain after conservative cost assumptions?
- Does one token, wallet or market regime dominate the result?
Why versioned Parquet data helps
Backtesting is iterative. You may calculate 100 feature variants against the same event universe before finding an approach worth further validation.
Downloading and decoding the same chain history for each experiment is slow and makes results harder to reproduce. Versioned Parquet files let you retain an immutable input, scan only the columns needed and associate each research run with a specific schema/data version.
datastore.sh’s Solana datasets are delivered as typed, versioned Parquet with documented schemas, manifests and SHA-256 checksums. Its catalog includes Pump.fun and PumpSwap historical datasets with decoded instructions and events, useful when the strategy needs the complete bonding-curve-to-AMM lifecycle.
Common Solana backtesting mistakes
Mistake 1: Entering at a candle close that was not yet known
Use the earliest executable price after the signal under your stated latency model.
Mistake 2: Filtering the universe to tokens that later worked
Build the universe from historical launch events, not today’s winners.
Mistake 3: Giving a model future wallet intelligence
Construct wallet features only from their observed past up to the event being predicted.
Mistake 4: Ignoring the pool model
Bonding curves, CPMMs, CLMMs and DLMMs need different execution state. A last price is not a universal fill price.
Mistake 5: Ignoring lifecycle changes
Pump.fun curve trading and PumpSwap AMM trading are not the same venue. Map the historical migration explicitly.
Mistake 6: Tuning until the test period looks good
Use chronological train/validation/test periods. Freeze the rule before the final out-of-sample evaluation.
Mistake 7: Treating a clean dataset as a profitable strategy
Clean data makes testing possible. It does not guarantee a durable edge, robust execution or live performance.
Frequently asked questions
What Solana data do I need for backtesting?
At minimum, you need a historical universe, ordered market events, a defined execution price/cost model and outcome data. Add venue state—such as reserves, ticks or bins—when you want to simulate execution rather than merely observe later prices.
Can I backtest Solana strategies using candles?
You can test broad price-observation hypotheses with candles. Candles are not enough for execution-quality tests of fast or illiquid Solana markets because they do not show exact event order, available liquidity or your price impact.
How do I avoid look-ahead bias in a Solana backtest?
Use event-time/as-of joins. Every feature must come from an event ordered at or before the decision event. Separate later outcomes from the feature pipeline and ensure aggregate windows are fully closed before use.
How do I backtest Pump.fun tokens after they migrate?
Build the token universe from Pump.fun creation events, use curve trades/state for pre-migration execution, map the historical completion/migration event to its PumpSwap pool, then use PumpSwap data for post-migration execution.
Is raw Solana transaction data enough for backtesting?
It can be, but you must build and maintain the decoders, event order, state reconstruction and validation yourself. Decoded protocol data is usually faster to work with when the strategy targets known protocols.
Does datastore.sh provide Solana data for backtesting?
Yes. datastore.sh provides historical Solana data as documented, typed and versioned Parquet files. The available protocol tables can be retained and queried in your own environment for research, feature generation and backtesting.
The key takeaway
A trustworthy Solana backtest begins with a historical record, but it does not end there.
You need the full historical universe, deterministic event order, point-in-time features, an honest execution model and a versioned input that you can reproduce later. Do that, and your result becomes a useful research artifact. Skip it, and an attractive return curve may only be measuring future information and impossible fills.
Explore historical Solana data on datastore.sh to inspect the protocol-level tables and coverage needed for your backtesting workflow.
Data Platform
datastore.sh engineering
The team that operates capture, decoding, and reconciliation for every dataset in the catalog.