There are two broad ways to backtest a strategy in Python, and the choice shapes both how fast you can iterate and how much you can trust the result. Knowing the difference, and when each is appropriate, saves you from a class of subtle bugs.
The two approaches
Vectorized backtesting computes over whole arrays at once. You express your signals as operations on pandas/NumPy series, and the engine evaluates them across the entire history in one pass.
Event-driven backtesting feeds the strategy one market event at a time, a bar, a quote, a timer, and lets it react, placing orders that fill on subsequent events. It mirrors the shape of live execution.
Vectorized: speed and breadth
Vectorized backtests are fast. When you want to sweep hundreds of parameter combinations or screen many instruments, computing over arrays is the efficient way to do it. For research and idea generation, that speed is a genuine advantage.
The catch is realism. Because the whole series is available at once, it’s easy to accidentally use information from the future, a value computed across the full array that wouldn’t have been known at decision time. Vectorized code can also gloss over the messy mechanics of orders, partial fills, and intrabar timing.
Event-driven: realism and live-parity
Event-driven backtests are slower, but they model the thing you actually care about: a strategy reacting to events as they arrive, with orders that fill afterward. This makes them much harder to fool with look-ahead bias, and it means the backtest behaves like the live system, often the same code path.
That parity is the real prize. If your event-driven backtest and your live run share a code path, a strategy that survives the backtest doesn’t need to be rewritten to go live, and differences in results point at fills or data rather than at two diverging implementations.
The look-ahead trap
Look-ahead bias, using data the strategy wouldn’t have had in time, is the single most common way backtests lie. Vectorized code is more prone to it because the future is sitting right there in the array. Event-driven engines make it structurally harder: the strategy simply hasn’t been handed future events yet.
When to use which
- Use vectorized for fast research: idea screening, broad parameter sweeps, exploratory analysis.
- Use event-driven for the realistic check and anything bound for live: it models execution faithfully and keeps you honest about timing.
Many workflows use both, vectorized to explore widely, event-driven to validate the survivors before committing.
How Periscøpe backtests
Periscøpe is event-driven. Strategies react to market events tick by tick, the same way they will in production, with no vectorized shortcuts that paper over what live execution looks like. The same engine and the same loop serve backtest, paper, and live, so the backtest isn’t just realistic, it’s literally the path your strategy will run when it goes live.