Skip to content
datastore.sh

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.

Data Platform15 min read

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 componentMinimum historical data
Token universeCreation/launch records, including tokens that later failed
Entry signalOrdered trades, wallet activity, pool/curve state and any other feature inputs
Entry priceHistorical executable liquidity, not a later chart close
Position trackingTrades, token balances or a clearly defined accounting model
Exit signalLater events only after they become observable
Exit priceHistorical venue/pool state, fees and a fill rule
Lifecycle changesMigration, pool creation, liquidity changes and venue switches
ReproducibilityDataset 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:

text
open: 0.000010 SOL
high: 0.000040 SOL
low:  0.000009 SOL
close:0.000025 SOL

That 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 modelState needed for a realistic backtest
Pump.fun bonding curveVirtual/real reserves, amounts, fees and current curve state
Constant-product AMMToken reserves, fee parameters and pool state
Concentrated-liquidity AMMCurrent price plus tick/range liquidity
DLMMActive bin and relevant bin liquidity/fee state
Aggregator routeCandidate 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:

text
(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.

sql
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 pathBacktest treatment
Never reaches entry signalNo position
Entry signal, then curve trade remains possiblePrice/exit against curve state
Curve completes and migratesMap mint to the historical PumpSwap pool
No liquidity at a required exitApply your predefined no-fill/partial-fill policy
Risk rule fires before migrationExecute against the then-current curve state

Step 5: calculate the return honestly

One explicit formulation is:

text
net return = exit proceeds
           - entry cost
           - entry fees
           - exit fees
           - network/priority fees
           - modeled price impact

Use 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 typeRequired dataHelpful additions
New-token momentumCreation + ordered trades + curve/pool stateWallet features, metadata, liquidity changes
DEX mean reversionPool swaps + pool stateTick/bin state, route information, market benchmark
Wallet-followingWallet actions + asset/venue statePoint-in-time wallet history, balances, cluster features
Migration strategyLaunches + curve completion/migration + destination poolPre/post-migration liquidity and latency assumptions
Liquidation or perp strategyFills, funding, order book, liquidationsPosition state and market-wide liquidity
Market-making simulationOrder book or pool state + trade flowQueue/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.

text
immutable source data
→ validated event tables
→ point-in-time state/features
→ strategy decisions
→ executable fill simulation
→ outcomes and metrics

Immutable 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.