Quant Modelling [HFT] All modules
5 Module 05

Backtesting Systems & Biases

How quants turn a trading idea into evidence — and the silent biases that make a beautiful backtest lie. Look-ahead, survivorship, overfitting, leakage, and the cost of reality.

Exam: Quant Research & Evaluation Source: Lecture 5 Validation

What is backtesting?

A trading idea is not evidence. Before risking capital, a quant must answer one question objectively: does this signal actually work? Backtesting is how we answer it.

Definition — Backtesting

Backtesting applies a set of trading rules to historical data to measure the returns and risk they would have produced, so you can evaluate a strategy's behavior before deployment.

The point is to replace gut feeling with measurement: estimate the return, study the drawdowns, and surface weaknesses early — while they are cheap to fix.

📜

Apply rules

Run your buy/sell logic over past prices exactly as it would have traded.

📊

Measure

Quantify return, volatility and maximum drawdown.

🔎

Evaluate

Decide if the edge is real and robust enough to deploy.

Research vs production

These are two different worlds with different standards. Research is experimentation: cheap, fast, tolerant of failure. Production trades real capital, so it demands far stricter controls, monitoring and reproducibility.

DimensionResearchProduction
PurposeExperimentation & discoveryDeploying real capital
Cost of errorWasted timeLost money
StandardsFlexible, iterativeStrict controls & checks
DataHistorical samplesLive market feed

The big misconception

A good backtest ≠ a good strategy

An impressive equity curve proves almost nothing on its own. Hidden biases inflate results, making a worthless idea look like gold. The backtest number is only as trustworthy as the validation behind it.

This is the single most important lesson of the module: a stunning historical result can be entirely an artifact of bias. The rest of this page is a catalogue of the biases that fabricate performance — and how to defend against them.

flowchart TB
  BT([Beautiful Backtest])
  BT --> LA[Look-ahead bias]
  BT --> SV[Survivorship bias]
  BT --> OF[Overfitting]
  BT --> DL[Data leakage]
  BT --> FR[Ignored frictions]
  LA & SV & OF & DL & FR --> FALSE([Inflated, false confidence])
  classDef s fill:#eef2ff,stroke:#4f46e5,stroke-width:1px,color:#3730a3;
  classDef d fill:#ecfdf5,stroke:#0d9488,color:#0d9488;
  class LA,SV,OF,DL,FR s
  class BT,FALSE d
      
Five distinct biases all lead to the same trap: a backtest that promises returns the live market will never deliver.

Look-ahead bias

This is the most dangerous backtest bias because it is the easiest to introduce by accident and it produces spectacular, completely fake results.

Definition — Look-ahead bias

Look-ahead bias is using information in the backtest that would not have been available at the moment of the trade. The strategy effectively peeks into the future.

The newspaper analogy

Imagine reading tomorrow's newspaper today. Picking winning trades would be trivial — and meaningless. A backtest with look-ahead bias is doing exactly this: it is cheating, not predicting.

A concrete trading example

Suppose a stock closes Monday at 100 and Tuesday at 110. If your backtest "buys on Monday because it knows Tuesday is higher," it has used Tuesday's price to make Monday's decision. On Monday that price did not exist yet. The 10% gain is invalid — it could never be captured live.

Look-ahead bias in code

In practice this bias usually hides in a single misaligned line. When a signal is computed from the same bar's data, multiplying it directly by that bar's return lets the position "know" the outcome it is supposed to predict.

# BAD — signal and return share the same timestamp (peeks into the present)
pnl = signal * returns

# GOOD — act on the PREVIOUS bar's signal, only after it is known
pnl = signal.shift(1) * returns
The fix in one idea

You can only trade after the signal is generated. signal.shift(1) delays the signal by one bar so the trade uses information that genuinely existed at decision time.

Worked example How look-ahead fabricates profit
  1. Prices: Mon close $= \$100$, Tue close $= \$110$. The "signal" is simply "go up tomorrow", computed from Tuesday's known close.
  2. Cheating (same-bar): apply the signal to the same day's move — the backtest books the full Mon→Tue jump: $\frac{110-100}{100} = 10\%$.
  3. Honest (shifted): the signal is only known after Tuesday closes, so it can act earliest on Wednesday. Tuesday's $10\%$ gain is no longer claimable.
  4. The entire $10\%$ existed only because the strategy saw the future. Shift the signal and the phantom profit disappears.
Look-ahead bias manufactured a 10% return out of nothing. Realistic, shifted execution earns it nothing for that move — proving the "edge" was an illusion.

How it happens and how to prevent it

Industry blowups trace back to mundane causes: timestamp mistakes, data-availability errors, and the false confidence they breed. The defenses are equally concrete.

🕒

Validate timestamps

Confirm every feature is stamped at — or before — the decision moment.

📡

Check availability

Ask: was this data actually published yet when the trade fires?

⚙️

Realistic execution

Trade on the next available bar/price, never the signal's own bar.

Survivorship bias

Definition — Survivorship bias

Survivorship bias is studying only the assets that survived, while the failures have quietly vanished from the dataset. You measure the winners and call it the average.

🏦

Mutual funds

Poorly performing funds get closed and disappear from databases. Backtesting on "all funds available today" silently drops every failure, so returns look better than reality.

📈

Index members

Today's index constituents are the survivors. Testing a strategy on the current members ignores the firms that were dropped or went bankrupt — historical constituents matter.

Why it inflates results

Removing the failures mechanically improves the measured return. The lesson is blunt: dataset quality matters. Use point-in-time data that still contains the losers.

Overfitting

Definition — Overfitting

Overfitting is learning the noise in historical data instead of the underlying signal. The result fits the past almost perfectly but generalizes poorly to the future.

Markets contain genuine randomness, and humans see patterns everywhere — even in pure noise. A model with enough freedom will happily memorize that noise.

Why researchers overfit
  • Too many parameters — extra knobs let the model contort to fit history exactly.
  • Repeated optimization — re-running and tweaking on the same data manufactures false discoveries.
  • Excellent in-sample, poor out-of-sample — the tell-tale fingerprint.

Train vs test: checking generalization

The defense is to split the data: train the model on one sample, then evaluate on an unseen sample. If performance holds up on data the model never saw, the edge is more likely real. The professional pattern uses three splits.

flowchart LR
  D([Historical Data]) --> TR([Train
fit the model]) TR --> VA([Validate
tune parameters]) VA --> TE([Test
final unseen check]) TE -->|Holds up| OK([Generalizes ✓]) TE -.->|Collapses| BAD([Overfit ✗]) classDef s fill:#eef2ff,stroke:#4f46e5,stroke-width:1px,color:#3730a3; classDef d fill:#ecfdf5,stroke:#0d9488,color:#0d9488; class D,TR,VA,TE s class OK,BAD d
Train → Validate → Test. The final test set is touched once; a big gap between train and test scores is the signature of overfitting.

Data leakage

Definition — Data leakage

Data leakage occurs when future information sneaks into the training data or features. It is a close cousin of look-ahead bias, but subtler — and hard to detect.

Financial examples
  • Future earnings accidentally included as a feature before they were reported.
  • Revised economic data — using the final revised figure instead of the first print that was actually available at the time.
Why leakage is dangerous

It creates false confidence in a strategy that cannot work live, which leads directly to poor capital allocation. Because it is so hard to spot, it survives careless reviews and reaches production.

The reality problem: market friction

Even a perfectly clean, bias-free strategy faces a final hurdle. Backtest profit is not real profit, because trading in the real world costs money.

Net return after frictions $$ r_{net} = r_{gross} - \text{costs} - \text{slippage} $$

Transaction costs

💵

Commissions

Broker charges on every order you send.

🏛️

Exchange fees

Venue fees for accessing the market.

↔️

Bid-ask spread

You buy at the ask and sell at the bid — the gap is a cost.

Slippage

Slippage

The expected price ≠ the execution price. Each individual fill is off by only a little, but across thousands of trades the cumulative impact is large.

Slippage is tied to the order book: liquidity sits at different price levels, and a large order eats through several levels, getting progressively worse fills. This drives two further constraints:

💧

Liquidity constraints

A small strategy may not scale — large trades move prices against you, so paper returns evaporate at size.

⚖️

Position sizing

Risk scales with allocation. Even a genuinely good signal can be dangerous if it is sized too aggressively.

Worked example From gross to net return
  1. A strategy shows a gross return of $r_{gross} = 10\%$ in the backtest.
  2. Subtract transaction costs (commissions, fees, spread): $\text{costs} = 3\%$.
  3. Subtract slippage from imperfect fills: $\text{slippage} = 2\%$.
  4. Apply the formula: $r_{net} = 10\% - 3\% - 2\%$.
$r_{net} = 5\%$ net. Half the headline return was consumed by friction — and a backtest that ignores costs would have reported the full, misleading 10%.

The backtest checklist & professional workflow

Every credible backtest clears the same gauntlet before anyone trusts its number.

Backtest checklist
  • No look-ahead bias — every trade uses only information available at the time.
  • No data leakage — no future information in features or training.
  • No survivorship bias — failed assets are still in the dataset.
  • Costs included — commissions, fees, spread and slippage all subtracted.
  • Validation performed — train/validate/test split confirms generalization.
flowchart LR
  A([Idea]) --> B([Research])
  B --> C([Backtest])
  C --> D([Validate])
  D -->|Passes checklist| E([Deploy & Monitor])
  D -.->|Fails checks| B
  classDef s fill:#eef2ff,stroke:#4f46e5,stroke-width:1px,color:#3730a3;
  classDef d fill:#ecfdf5,stroke:#0d9488,color:#0d9488;
  class A,B,C,D s
  class E d
      
The professional loop: Idea → Research → Backtest → Validate → Deploy. Failing validation sends the idea back, not into production.
Self-check: A backtest uses tomorrow's closing price to decide today's trade. Which bias is this?
Look-ahead bias. The strategy is using information (tomorrow's close) that did not exist at the moment of the decision. The fix is to shift the signal so trades only act on already-available data.
Self-check: A model scores 99% on training data but performs poorly on unseen test data. What went wrong?
Overfitting. The model learned the noise in the training sample instead of a real signal, so it fails to generalize. A large train-vs-test gap is the classic symptom.
Self-check: A strategy backtests at 10% gross. Costs are 3% and slippage is 2%. What is the net return?
$r_{net} = 10\% - 3\% - 2\% = \mathbf{5\%}$. Frictions roughly halved the headline return — which is why a cost-aware backtest is non-negotiable.

Key takeaways

Remember
  • Good backtests can be wrong — biases inflate results, so a strong curve is not proof.
  • Validation matters — train/validate/test is how you separate signal from noise.
  • Costs matter — $r_{net} = r_{gross} - \text{costs} - \text{slippage}$; ignore frictions and you trade on a lie.
  • Overfitting is dangerous — and look-ahead bias is the most dangerous of all.
  • Most of the real work is proving the alpha is real, not finding it.