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.
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.
-
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.
-
12:01:00.100
The order reaches the exchange after 100 ms of latency. The price it was based on is already history.
-
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.
-
12:02:00.000
That bar closes at 42,573.63. The position is already down $99.01 before fees.
| Naive backtest | tape | |
|---|---|---|
| Fill price | 43,555.00 | 43,563.73 |
| Based on | The close it just used to decide | The next bar's open, plus slippage |
| Filled at | 12:01:00.000, instantly | After 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
Placeholder dataA moving-average crossover on BTC/USDT, every minute from to , starting with . A naive backtest turns it into . In tape it ends at .
| Naive backtest | tape | Buy and hold | |
|---|---|---|---|
| Total return | |||
| Sharpe ratio | |||
| Worst drawdown | |||
| Trades | |||
| Fees paid |
Where the returns went
The same backtest again, adding one honest assumption at a time.
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.
Console
Can an AI find a strategy that survives?
Placeholder dataAI agents searched for trading strategies in a loop, with tape as the referee. They trained on and never saw until the final exam.
- Propose. A researcher agent suggests a trading idea.
- Write. A coding agent turns it into a strategy, compiled to WebAssembly and run in a sandbox with no clock, network or files.
- Test. tape backtests it on the training period only.
- Critique. A critic agent looks for leaks and overfitting, then sends the strategy back or rejects it.
- 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.
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.
Was the best one just lucky?
Try enough random ideas and one of them will look brilliant in training. This checks the best strategy against what luck alone would produce.
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.