tape

Most backtests lie.

tape is a backtesting engine for trading strategies, built to make the usual mistakes impossible. A strategy only ever sees what has already happened, and every order is filled the way a real exchange would fill it: late, at a worse price, and for a fee.

Real BTC/USDT prices, one minute at a time, from 3 January 2024. Nothing to the right of the line has been printed yet. That's all a strategy ever gets to see.

Five ways a backtest lies

A backtest replays history to see how a strategy would have done. Most of them flatter the strategy in the same few ways. Each one on its own can turn a losing idea into a winning chart.

It knows how the minute ends before it starts.
A one-minute bar's high, low and close aren't known until the minute is over. In tape, a bar only becomes visible when it closes, and a strategy has no way to read anything else.
It buys at the price it just saw.
By the time an order reaches the exchange, the price has moved on. tape delays every order, fills market orders at the next available price plus slippage, and fills resting limit orders only when the market trades through them.
It trades as much as it likes.
Real markets have finite volume. tape caps how much of each bar an order can take, so large orders fill in pieces, or not at all.
It trades for free.
Every fill in tape pays the exchange's maker or taker fee. For strategies that trade often, fees alone are frequently the difference between a profit and a loss.
Its numbers don't add up.
Floating-point money drifts, and results can change from one run to the next. tape keeps prices, quantities and cash as exact integers and replays events in a fixed order. The same inputs give identical results, every time.

One trade, done properly

A real minute from 3 January 2024, just as bitcoin fell about 6% in ten minutes. A strategy decides to buy 0.1 BTC when the 12:00 bar closes. Here's what tape does with that decision.

  1. 12:01:00.000

    The 12:00–12:01 bar closes at 43,555.00. Only now can the strategy see it. It sends a market order to buy 0.1 BTC.

  2. 12:01:00.100

    The order reaches the exchange after 100 ms of latency. The price it was based on is already history.

  3. Next price

    It fills at the next bar's open, 43,555.01, plus 2 bps of slippage: 43,563.73. The taker fee is 0.1%, or $4.36.

  4. 12:02:00.000

    That bar closes at 42,573.63. The position is already down $99.01 before fees.

The same decision in two backtests
Naive backtesttape
Fill price43,555.0043,563.73
Based onThe close it just used to decideThe next bar's open, plus slippage
Filled at12:01:00.000, instantlyAfter 100 ms of latency
Fee$0.00$4.36

That's $5.23 worse on a single purchase: 87 cents of price and $4.36 of fees. It looks small. A strategy that trades a few hundred times a month pays it on every trade, on the way in and on the way out.

The same strategy, both ways

A moving-average crossover on BTC/USDT, every minute from to , starting with . A naive backtest turns it into . In tape it ends at .

Results
Naive backtesttapeBuy and hold
Total return
Sharpe ratio
Worst drawdown
Trades
Fees paid

Run a backtest

This is tape itself, compiled to WebAssembly and running in your browser on a month of real BTC/USDT one-minute data. Pick a strategy or write your own in JavaScript, decide how honest the execution should be, and run it.

Execution

Can an AI find a strategy that survives?

AI agents searched for trading strategies in a loop, with tape as the referee. They trained on and never saw until the final exam.

  1. Propose. A researcher agent suggests a trading idea.
  2. Write. A coding agent turns it into a strategy, compiled to WebAssembly and run in a sandbox with no clock, network or files.
  3. Test. tape backtests it on the training period only.
  4. Critique. A critic agent looks for leaks and overfitting, then sends the strategy back or rejects it.
  5. Final exam. Every strategy runs once on data no agent has seen, against buy-and-hold. Only strategies the critic passed can count as a success.
ideas proposed
compiled
ran without crashing
passed the critic
passed the critic and beat buy-and-hold on unseen data

Training results versus the final exam

Each dot is a strategy. If backtests told the truth, dots would sit on the diagonal.

Strategies that traded a lot lost in both periods. The tight cluster around buy-and-hold's own scores is mostly strategies that barely traded at all: buy-and-hold in disguise. Nothing showed an edge beyond owning bitcoin.

From the lab notebook

    Every attempt was counted, because trying hundreds of ideas and keeping the best one is its own kind of cheating. And every result is reproducible: re-running all of the strategies from their saved WebAssembly gave bit-identical results.

    Under the hood

    • Written in Rust, with unsafe code forbidden.
    • Prices and cash are integers in units of 10−8, so 0.1 + 0.2 is exactly 0.3.
    • Timestamps are in nanoseconds, so latency can be modelled below a millisecond.
    • Market data comes from Binance's public archive, checked against its published SHA-256 checksums.
    • Every run produces a hash of its fills. Two runs with the same inputs always match.
    • AI-written strategies run as WebAssembly with a hard limit on compute and no access to anything outside.
    • The same engine compiles to WebAssembly for the demo on this page.
    • Tests fail if a single event goes missing or arrives out of order.