One of the most frustrating experiences in algorithmic trading is seeing a strategy produce incredible backtest results...
…and then watching it perform completely differently in live trading.
Maybe the backtest showed an 85% win rate.
Maybe the equity curve looked almost perfect.
Then you deploy it.
Suddenly, the results disappear.
It's easy to blame latency, slippage, execution, or changing market conditions.
But sometimes the problem is much simpler:
Your backtest was using information from the future.
This is called look-ahead bias.
I've encountered this while building and testing Polymarket trading bots, and it's one of those problems that can make a bad backtest look extremely convincing.
The basic rule is simple:
A strategy can only use information that was available at the exact moment it made a decision.
Nothing from the future.
Sounds obvious, right?
But when you're working with historical data, the entire future is already sitting inside your dataset.
Your program can see everything.
A live trading bot can't.
That's where the problem starts.
Imagine your strategy enters a trade at the beginning of a candle.
This looks reasonable at first:
signal = df["close"][i] > df["open"][i]
enter_at = df["open"][i]
But there's a problem.
You're using the candle's closing price to make a decision at its opening.
That closing price doesn't exist yet.
A more realistic version would be:
signal = df["close"][i - 1] > df["open"][i - 1]
enter_at = df["open"][i]
Now the strategy uses the previous completed candle.
It's a tiny difference in code.
It can be a huge difference in results.
This is what makes backtesting dangerous.
Suppose you're testing a strategy from January through June.
Your dataset already contains:
January
February
March
April
May
June
But when your strategy makes a decision in January, it should only know what was available in January.
It shouldn't have access to information from March or June.
The historical dataset doesn't enforce this automatically.
You have to enforce it yourself.
Here's another common example.
Your strategy trades at 9:00 AM and uses:
But how much of that information was actually known at 9:00 AM?
The complete day's high and low obviously aren't known yet.
Neither is the final volume.
Yet when you load historical data, those values are already present.
That's why every feature should have an important property:
A known timestamp.
You need to know not just what the value is, but when your strategy could have known it.
Look-ahead bias isn't limited to trading signals.
It can also appear during machine-learning preprocessing.
For example:
# WRONG
scaler.fit(all_data)
X = scaler.transform(all_data)
The scaler has now seen the entire dataset.
That means information from future observations can influence how historical observations are transformed.
A better approach is to fit preprocessing only on information available at that point:
# CORRECT
scaler.fit(data[:t])
X_now = scaler.transform(data[t])
This is one reason walk-forward testing is so important.
Rolling calculations can also introduce future information.
For example:
df["ma"] = df["close"].rolling(
20,
center=True
).mean()
A centered moving average can use values from both sides of the current timestamp.
That means it can include future prices.
A normal trailing window is safer:
df["ma"] = df["close"].rolling(20).mean()
The indicator should only use information that has already happened.
This is especially dangerous when building predictive models.
Imagine you're trying to predict the outcome of a prediction market.
If your features accidentally contain:
your model isn't really predicting the outcome.
It's seeing the answer.
That's how you can end up with a model showing 99% accuracy in testing while failing badly in live trading.
How I Think About It
Whenever I build a feature, I try to ask one question:
Would my live bot actually know this value at this exact moment?
If the answer is no, I shouldn't use it.
I also prefer backtests where the historical boundary is explicit:
for t in range(start, end):
history = data[:t]
decision = strategy(history)
outcome = data[t]
record(decision, outcome)
The strategy receives the past.
The backtest evaluates what happens next.
That separation is important.
This Became Important in My Polymarket Research
When I started working more seriously on Polymarket strategies, I realized that having good historical data was just as important as having a good strategy.
About three months ago, I started recording historical data directly from on-chain sources and the Polymarket API instead of relying only on reconstructed datasets.
I archive 5-minute cryptocurrency market data locally and use it for strategy research and backtesting.
This gives me much better control over:
I've used this data and infrastructure while developing and testing several Polymarket strategies, including an end-cycle sniper and a BTC/ETH hedge bot.
The goal isn't to create a beautiful equity curve.
The goal is to create a simulation that is as close as possible to what the bot could actually have experienced.
A Good Backtest Still Isn't a Guarantee
Removing look-ahead bias doesn't magically make a strategy profitable.
There are still many real-world problems:
Latency
Your historical model may assume an order executes instantly.
Slippage
The price you see isn't always the price you receive.
Liquidity
A strategy may work with 10 shares but behave very differently with 1,000.
Order-book depth
The best quote isn't necessarily enough to fill your entire order.
API delays
Market data and order responses aren't instantaneous.
Partial fills
Your backtest may assume complete fills when real trading doesn't.
Changing market conditions
A strategy that worked six months ago may behave differently today.
A backtest is a simulation.
It isn't a guarantee.
The Question I Think Matters Most
Don't just ask:
"Did this strategy make money historically?"
Ask:
"Could my bot actually have made this decision with the information available at that moment?"
That question changes how you build a backtesting system.
You're no longer trying to reproduce a historical chart.
You're trying to reproduce the information environment that existed when the trade happened.
And that's a much harder — but much more useful — problem.
Final Thoughts
Look-ahead bias is one of those bugs that can hide in plain sight.
Your code works.
Your backtest runs.
Your charts look great.
And yet the strategy may be using information that a real trader or bot could never have known.
So whenever a backtest looks unusually perfect, don't immediately celebrate.
Check the timeline.
For every feature, indicator, and input, ask:
When did this information become available?
If the answer is after the decision, your backtest is looking into the future.
I'm continuing to work on Polymarket trading infrastructure, historical data collection, automated execution, and realistic backtesting.
You can explore some of my work here:
GitHub:
https://github.com/Benjam1nCup/Polymarket-trading-bot-python-V2
Telegram:
https://t.me/BenjaminCup
If you're building trading bots, prediction-market strategies, or quantitative research infrastructure, feel free to connect.
Live agents fail the same way pretty backtests do: the dataset already contains the future, so the decision looks brilliant until you freeze the clock. I’d pin every retrieval to an as-of timestamp, refuse to let a later note rewrite why an earlier action was allowed, and treat “we know now” as a different claim from “we knew then.” Soft “use the vault” with no observation time is look-ahead dressed as memory. Curious which single leak you’d ban first in an agent log: reading a doc dated after the decision, scoring a plan with metrics collected after the change, or letting a compaction summary invent outcomes that hadn’t landed yet.
Good write-up. What would you do differently if you started again?
Thanks for writing this up. Bookmarking it for later.