A backtest means running your trading idea on historical data to see whether it would have made money. The whole point is to find out before you risk a cent. It sounds simple — code the rules, press run, read the profit. The catch is that most backtests lie, and not because the math is wrong. They lie because of silent biases baked into how they were built. This guide covers the workflow and the six traps that inflate returns, so your test tells the truth.
1. What a backtest actually is
You take a set of rules — when to buy, when to sell, how much to hold — and replay them bar by bar against past prices. The output is a performance report, not a guarantee:
- Total return / CAGR — how much the strategy grew over the period.
- Max drawdown — the worst peak-to-trough drop. This is what makes you quit in real life.
- Win rate — share of trades that closed in profit.
- Sharpe / risk-adjusted return — return per unit of volatility.
- Trade count — too few trades and your result is a coin flip wearing a costume.
A good backtest answers one question honestly: given only what I knew at the time, would this have worked?
2. The basic workflow
- Define the rules precisely. "Buy the dip" is not a rule. "Buy when close crosses above the 20-day average, sell after a 5% gain or 3% stop" is. Vague ideas produce vague, useless tests.
- Get clean historical data. OHLC bars, adjusted for splits and dividends, with no gaps. Garbage in, garbage equity curve out.
- Simulate trade-by-trade using only information available at that moment — never the future.
- Measure with the metrics above, and include costs (see trap #4).
- Validate out-of-sample on a period you never touched while building.
3. The 6 traps that inflate returns
These are the reasons a "great" backtest collapses the day you go live:
- Look-ahead bias. Using data you couldn't have had at the time — tomorrow's close, a future earnings date, un-adjusted splits. Fix: build signals from past bars only, and
shift(1)your position so you act next bar, not this one. - Overfitting (curve fitting). Tweaking parameters until the history looks perfect. The more knobs you turn, the more the strategy memorizes the past instead of capturing a real edge. Fix: keep parameters few, and prefer logic over magic numbers.
- Survivorship bias. Testing only stocks that still exist — the delisted losers quietly vanish, leaving your "winners" artificially rosy. Fix: use a point-in-time universe that includes names that died.
- Ignoring costs. A 0.1% edge dies under 0.5% round-trip cost, slippage, and borrow fees. Fix: subtract realistic commissions and slippage per trade, every time.
- Data snooping. Trying 200 ideas and publishing the one that "worked." That one is noise wearing a lab coat. Fix: hold a test set you never peek at during research.
- No out-of-sample test. Fitting and grading on the same data. Fix: split history into in-sample (build) and out-of-sample (prove), and only touch the second set once.
4. A minimal, bias-aware Python sketch
This snippet shows the key habit — compute the signal, then shift it by one bar so you can only act on information that already existed:
import pandas as pd
df = pd.read_csv("prices.csv", parse_dates=["date"]).sort_values("date")
# signal uses ONLY past bars (rolling mean of history so far)
df["ma20"] = df["close"].rolling(20).mean()
df["signal"] = (df["close"] > df["ma20"]).astype(int)
# act NEXT bar — this is what kills look-ahead bias
df["position"] = df["signal"].shift(1)
df["ret"] = df["close"].pct_change()
df["strat_ret"] = df["position"] * df["ret"] # before costs
# now subtract realistic costs per trade to see the real edge
print(df[["close", "strat_ret"]].tail())
Notice there is no peek at the future, and no costs yet — adding both is exactly where most people stop too early.
5. When to do it yourself vs hire a quant
If your idea is a simple rule on clean single-asset data, DIY is fine and a great learning exercise. Hire a quant when any of these are true:
- You need point-in-time fundamentals or a survivorship-free universe.
- Your idea spans multiple assets or needs factor/risk modeling.
- You want honest validation, not confirmation that your pet theory works.
- You would rather get a reproducible report and the code than spend weeks debugging data.
👋 Want it done for you?
If you have a trading idea but no time to build a clean, bias-checked backtest, I turn your logic into tested, reproducible Python code — with the equity curve, drawdown and win rate, and the traps above already handled. See the Quant Strategy & Backtest service page, or just email me. Research and educational use only — not financial advice.