TradeLabs AILearn

Event-Driven vs Vectorized Backtesting

Vectorised backtests compute signals and returns for all dates at once using arrays. Learn how they work, a pandas example, their speed advantages and their traps.

Advanced3 min readUpdated 3 Oct 2026
Markdown
Lesson 17 of 38

A vectorised backtest calculates a strategy's signals, positions and returns for every date at once, using array operations instead of looping through time one bar at a time. In Python, libraries such as NumPy and pandas make this very fast: you can test thousands of variations in seconds. Vectorised backtests are ideal for research and quick screening, but their speed comes with traps, especially look ahead bias and oversimplified execution. Event driven backtests are slower but closer to live trading.

How it works#

  1. Load price data into an array or DataFrame.
  2. Compute indicators for all dates (moving averages, z scores).
  3. Compute signals as arrays of positions (+1, 0, minus 1).
  4. Shift positions by one bar so trades use only past information.
  5. Multiply positions by returns to get strategy returns.
  6. Subtract costs when positions change.
  7. Compute performance metrics.

A pandas example#

import pandas as pd
import numpy as np

df = pd.read_csv("prices.csv", index_col="date", parse_dates=True)
df["ret"] = df["close"].pct_change()

fast = df["close"].rolling(20).mean()
slow = df["close"].rolling(100).mean()
df["signal"] = np.where(fast > slow, 1, 0)

df["position"] = df["signal"].shift(1)          # trade on the next bar
cost_per_trade = 0.0005                          # 5 basis points per change
df["trades"] = df["position"].diff().abs()
df["strat_ret"] = df["position"] * df["ret"] - df["trades"] * cost_per_trade

equity = (1 + df["strat_ret"].fillna(0)).cumprod()
sharpe = df["strat_ret"].mean() / df["strat_ret"].std() * np.sqrt(252)
print(round(equity.iloc[-1], 2), round(sharpe, 2))

The shift(1) line is essential: without it, the backtest would use today's close to decide today's position. See Look-Ahead Bias.

Advantages#

AdvantageWhy it matters
SpeedTest many parameters and markets quickly. See Parameter Optimization
SimplicityShort, readable code
Easy analysisResults fit naturally into DataFrames for statistics and plots
Good for signal researchQuick check of whether an idea has any edge

Limitations and traps#

TrapExplanation
Look ahead biasAll data is present at once, making future leaks easy
Simplified executionAssumes fills at close or open prices without queue or slippage modelling. See Fill Models, Partial Fills and Order Queues
Path dependent logicStops, trailing stops and position sizing that depends on equity are awkward to vectorise
Portfolio constraintsCash limits, margin and position caps are harder to model. See Portfolio and Multi-Asset Backtesting
Intrabar eventsCannot tell whether stop or target was hit first within a bar

When to switch to event driven#

Move to an event driven backtest when the strategy has stops and targets, complex order types, equity based position sizing, portfolio constraints or needs the same code to run live. Libraries such as Backtrader, Zipline and NautilusTrader support event driven designs, while vectorbt offers fast vectorised testing with some path dependent features. See Backtesting Libraries Compared.

Good practice#

  1. Shift signals before multiplying by returns.
  2. Charge costs on position changes.
  3. Check results with a simple event driven loop for a sample period.
  4. Keep code and data versioned. See Backtest Reproducibility.

Testing many variations quickly#

Vectorised code makes it easy to loop over parameter grids or many assets in seconds. That speed is a double edged sword: it encourages testing thousands of variations, which raises the risk of finding chance results. Record how many variations you test and judge the best result with that count in mind. See P-Hacking and Multiple Testing.

Frequently asked questions#

What is a vectorised backtest?#

A backtest that calculates signals, positions and returns for all dates at once using array operations rather than looping through each bar.

Are vectorised backtests accurate?#

They are accurate for simple strategies if signals are lagged and costs are included, but they struggle with stops, complex orders and portfolio constraints.

Why is shift(1) important in pandas backtests?#

Because it ensures today's position is based on yesterday's signal, preventing the backtest from using information that was not yet available.

Next, learn how trades actually get filled in Fill Models, Partial Fills and Order Queues.

Check your understanding

3 quick questions on this lesson. Get them all right to finish it.

Turn on JavaScript to take the quiz.

Finished this lesson?Sign in to save your progress across devices.
Next lessonFill Models, Partial Fills and Order QueuesA fill model decides when and at what price backtest orders execute. Learn market, limit and stop fill assumptions, queue position and adverse selection.

Mentioned in