---
title: 'Look-ahead bias backtest example: one timing bug'
url: https://comparand.xyz/blog/look-ahead-bias-backtest-example
description: 'One timing bug turned a losing hourly Bitcoin rule into a fake winner: Sharpe −8.00 became 59.41. See how it happens and how to check your test.'
updated: '2026-10-21'
category: Patterns
---

# Look-ahead bias backtest example: one timing bug

One timing bug turned a losing hourly Bitcoin rule into a fake winner: Sharpe −8.00 became 59.41. See how it happens and how to check your test.

Look-ahead bias is when a backtest uses information it could not have had yet. In our hourly Bitcoin test on Binance, one timing bug turned a rule that **lost 0.06% per hour** after fees into one that seemed to **gain 0.33% per hour**. Its Sharpe score jumped from **−8.00 to 59.41**, using the same 61,901 hours from September 2019 to September 2026.

A backtest runs a trading rule on old prices to see what it would have done. The bug here is one of the most common ones: using an hour's closing price to decide a trade at the start of that same hour.

For the six checks to run on an AI agent's backtest, see [AI trading agent risks](https://comparand.xyz/blog/ai-trading-agent-guardrails).

## What did the honest rule know before entering?

We tested Binance BTCUSDT, a Bitcoin perpetual future. A perpetual future, or perp, is a contract that follows Bitcoin's price and never expires.

The rule is simple. If the last finished hour went up, go long for the next hour (gain if price rises). If it went down, go short (gain if price falls). If the price did not change, stay out.

We used hourly bars. A bar records the open, high, low and close price over one hour. The closing price is only known when the hour ends.

So the honest version waits for an hour to finish, reads its direction, then picks a position for the next hour. When that position starts, nobody knows how the next hour will close.

## Where did the future price slip into the test?

The broken version used the direction of the hour it was about to trade. If the coming hour would rise, it went long. If it would fall, it went short. Before fees, it won almost every hour.

This bug is easy to write. In a spreadsheet or a table of prices, you calculate each hour's return in one column. Then you pick a position in the next column, on the same row. But that row's return uses the price at the end of the hour. The decision should have been made at the start.

For this rule, the fix is to use the previous row's return, which is the last finished hour. In Python's pandas library, that is usually one `shift(1)` on the decision column. Other tests may need other fixes. The real rule is: for every input, check when it was first known.

The same mistake shows up in other forms:

- Using a bar's high or low to pick an entry inside that same bar.
- Scaling prices with an average or range taken from the whole data set, future included.
- Testing only on coins that still trade today, which hides the ones that died.

*Diagram: Show an honest decision using the previous completed hourly bar and a broken decision reaching forward to the close of the hour being traded.*
## How much did the timing bug change the result?

Both versions used the same Binance BTCUSDT hourly prices, the same hours and the same 0.05% fee per trade. All times are in UTC, the world standard clock.

| Test period | Hours | Honest: average per hour, after fees | Broken: average per hour, after fees | Honest Sharpe | Broken Sharpe |
| --- | ---: | ---: | ---: | ---: | ---: |
| Sep 2019–Dec 2022 | 29,045 | −0.05% | +0.42% | −6.38 | 61.44 |
| Jan 2023–Sep 2026 | 32,856 | −0.06% | +0.26% | −10.82 | 62.74 |
| Sep 2019–Sep 2026 | 61,901 | −0.06% | +0.33% | −8.00 | 59.41 |

Sharpe compares the average result with how much results swing, scaled to a year. These are averages per hour, not totals.

The honest rule lost in both periods. This is not a rule to trade: it lost money even before fees over the full period. The broken rule looked like a huge winner in both periods.

Both versions paid the same total fees over the full period, because they changed positions the same total amount. So the fake gain did not come from lower costs. It came only from seeing the future.

## What warning signs did the fake winner show?

The broken test had numbers that real trading results almost never show:

- **It made money in 87.21% of hours** after fees. The honest version made money in 40.17%.
- **Its worst fall from a previous high was only 0.62%** over seven years of Bitcoin.
- **Its Sharpe scores were in the 50s to 70s every single year**, from 2019 to 2026.

A useful habit: when a backtest looks this smooth, assume a bug first. Check the timing before you check anything else.

## Why didn't the later period catch the bug?

A holdout is a later stretch of dates you keep hidden while building a rule, then test on once. It helps catch overfitting, which means picking a rule that fit old prices by luck. We show that problem in [our test of 1,000 random trading rules](https://comparand.xyz/blog/overfitting-1000-random-trading-rules).

But a holdout cannot catch a timing bug. The bug reads the future in every period, old or new. From January 2023 to September 2026, the broken version still averaged +0.26% per hour over 32,856 hours.

So "it worked on later dates too" does not prove a test is clean.

## Can a fake winner still have losing hours?

Yes. Even knowing the direction, the broken version did not make money after fees in about 13% of hours. When Bitcoin moved only a tiny amount, the fee for switching sides (0.05% to close, plus 0.05% to open) was bigger than the gain.

Fees also mattered a lot for the honest rule. In 2021, it gained 25.94% before fees but lost 98.58% after fees, across 8,760 hours. That is because it switched sides very often and paid the fee each time. Totals here are compounded: each hour's gain or loss changes the amount used in the next hour.

So some losing hours, or even a losing year, do not prove a test has clean timing.

## How we measured this

We used Binance BTCUSDT perpetual hourly bars from September 8, 2019 at 17:00 UTC up to October 1, 2026. Both versions used the same 61,901 hours where the current and previous hourly returns existed. The rule was fixed in advance; the only change was whether it read the previous hour's direction or the coming hour's. Both paid 0.05% each time a position opened or closed, including the first entry and the last exit. We left out funding payments, spread, slippage and delays, and assumed each trade filled at the previous closing price.

## How can you check your own backtest for look-ahead bias?

Try these three checks on any backtest:

1. **The timing list.** Pick one trade. Write down when it starts. Next to every input it uses (close, high, low, volume, any indicator), write when that value was first known. Every time must be at or before the start.
2. **The delete test.** Delete every price after one decision time and recompute that decision. It should not change. If it does, future data is getting in.
3. **The shift test.** Make your rule use data one bar older and rerun. If the result collapses from amazing to awful, like ours did, check the original for peeking before you trust it.

Do the same for chart look-alike searches. A [chart analog](https://comparand.xyz/blog/what-is-a-crypto-chart-analog) is a past chart with a similar shape. Check that each past chart ended before your decision time, and that what happened after it also finished before your decision time. Our [test of chart look-alikes](https://comparand.xyz/blog/do-chart-lookalikes-predict-crypto) used both rules.

*Diagram: Show a historical search cutoff with a past case whose later outcome is fully known and another whose outcome extends beyond the cutoff.*
## Try this in Comparand

Comparand's tools are built around "what was known at that time". With Comparand connected to your AI app, you can ask:

**"Find past Binance BTCUSDT hourly charts like the one ending at [your past time]."**

- You set the chart's end time (called end_utc; it defaults to now). The search uses completed bars only.
- Matches come only from Bitcoin's own Binance past, on the same bar size, and never overlap your chart.
- Each match shows its own path and later moves, with no average or hit rate. $0.01 per search from credits.

**"Show me every Hyperliquid coin's labels at [one past UTC minute]."**

- The snapshot tool (hl_labels_snapshot) returns the archive's per-minute labels for every coin at that one minute. You can pick which fields you want. $0.005 per call on pay-as-you-go.

**"Which days have Hyperliquid Bitcoin data during my test period?"**

- The coverage calendar (hl_coverage_calendar) lists which days hold 1-minute bars, 5-minute bars, funding and labels for that coin, with status and source details. It is free.

These are past cases, not a forecast. You can [try 3 coins free](https://comparand.xyz/try), and the [docs](https://comparand.xyz/docs) show how to connect your AI app.

## The short version

- One timing bug turned an hourly Bitcoin rule that lost 0.06% per hour into a fake winner gaining 0.33% per hour, after fees.
- The Sharpe score went from −8.00 to 59.41 on the same 61,901 hours.
- Testing on later dates did not catch it: the bug reads the future in every period.
- Too-smooth results (87.21% winning hours, a 0.62% worst drop) are a sign to check timing first.
- Use the timing list, the delete test and the shift test on your own backtests.

## Questions people ask

**What is look-ahead bias in a backtest?**

Look-ahead bias means a backtest uses information before it would have been known. A common example is picking a trade at the start of an hour using that same hour's closing price.

**How much can look-ahead bias change a backtest?**

In our hourly Binance Bitcoin test, the honest rule averaged a 0.06% loss per hour after fees. The same rule with a one-row timing bug averaged a 0.33% gain per hour, and its Sharpe score went from −8.00 to 59.41.

**Does testing on later dates catch look-ahead bias?**

No. The bug reads the future in every period. In our test, the broken version still averaged +0.26% per hour after fees from January 2023 to September 2026.

**Can a backtest with look-ahead bias still have losing hours?**

Yes. Our broken Bitcoin test did not make money after fees in about 13% of hours, because small moves did not cover the fee. Some losses do not prove a test is honest.

**How do I check my backtest for look-ahead bias?**

For each input, write down when it was first known and compare that with when the trade starts. Then delete all prices after a decision time and rerun: the decision should not change.
