Solana backtesting

Test your strategyon the chain that happened.

Replay recorded Solana mainnet through your existing Yellowstone gRPC client. Same protocol, same ordering, 100μs precision. Apache-2.0.

Why historical replay

Mainnet is the only honest backtest.

Devnet has no MEV, no congestion, no real adversaries. Custom simulators drift from validator behavior the moment a new program hits a new edge case.

Sillage records mainnet as it was delivered — every account write, every transaction, every block — and streams it back through the same protocol your live bot already speaks. The chain that happened, on demand, at the timing it happened.

How it works

Three steps from a live subscription.

  1. 01
    Point your client at a sillage endpoint.

    Same Yellowstone gRPC, same SubscribeRequest, same filters. Sillage speaks the protocol as a server.

  2. 02
    Pass a starting slot from the recorded window.

    The stream begins there and replays at wall-clock speed, intra-slot ordering preserved to 100 microseconds.

  3. 03
    Iterate without holding a live subscription open.

    Re-run the same window as many times as your tuning loop needs. The input never changes, so a difference in output is a difference in your code.

Drop-in

yellowstone-grpc-client, unchanged.

Only the endpoint and starting slot change. Your SubscribeRequest, filters, and message handling are untouched.

Backtest replay
let mut client = GeyserGrpcClient::build_from_shared(
    "https://replay.sillage.sh",
)?
    .x_token(Some(api_key))?
    .connect()
    .await?;

let req = SubscribeRequest {
    // any slot within the last 24 hours
    from_slot: Some(312_847_201),
    transactions: hashmap! {
        "swaps".into() => SubscribeRequestFilterTransactions {
            account_include: vec![JUPITER_V6.into()],
            ..Default::default()
        },
    },
    ..Default::default()
};

let (_, mut stream) =
    client.subscribe_with_request(Some(req)).await?;

while let Some(msg) = stream.next().await {
    handle(msg?);
}
Questions

Questions people ask first.

How do I get an endpoint?

Run one. Clone the repo and start a reader against a window you have recorded, or against the published sample archive. There is also a live demo endpoint at replay.sillage.sh if you want to see it working before setting anything up.

Do I need to change my client code?

No. Sillage speaks the Yellowstone gRPC protocol as a server. Point your existing client at the new endpoint and pass a starting slot — your SubscribeRequest, filters, and message handling work as-is.

How accurate is the replay?

Every message carries the timestamp it was received during live capture, preserved to 100 microseconds. Intra-slot ordering, propagation gaps, and the texture of real network time all replay as they happened.

How much history can I replay?

Whatever you record. Sillage is the recorder as well as the player — point the writer at a Geyser source for as long as you want history, and the reader serves exactly that back.

How is this different from running my own RPC?

An RPC gives you on-demand queries; it doesn't give you a replayable, time-ordered stream of every account write that happened yesterday. Sillage does, through the protocol your bot is already wired for.

How does this compare to a live Yellowstone provider?

Helius, Triton, and QuickNode all stream the chain forward beautifully. None of them let you replay a specific past window through the same protocol, and none of them are something you can run yourself. That's the inverse Sillage was built for.

Backtest the real chain.

Clone it, run it, or try the live endpoint.