VectorBT: matrix-shaped backtesting and what its Fair Code licence costs you
The backtesting engine that gives you an unfair advantage. Run thousands of trading ideas before others finish one.
At a glance
- What is it?
- VectorBT replaces the per-strategy loop with NumPy arrays, Numba and an optional Rust engine, so a grid of parameter combinations runs as one broadcast operation. The trade-off is a Fair Code licence and a PRO edition that takes the heaviest features with it.
- Who is it for?
- Adopt VectorBT if your research loop is grid search over signals on a handful of symbols and you are comfortable reading pandas MultiIndex output. Do not adopt it if you need tick-level or order-book simulation, or if a licence that reserves the heaviest features for a paid PRO edition is a blocker for your team.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 45 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The problem VectorBT solves is the shape of the research loop
Most backtesting libraries are organised around a strategy object. You instantiate one, feed it bars, and it walks forward through time. That design is fine when you want to know how one configuration performed. It becomes the bottleneck when you want to know how ten thousand configurations performed, because the outer loop is yours to write and the inner loop is Python. VectorBT inverts this. The README describes the approach as packing thousands of configurations into NumPy arrays and running them all at once, with Numba and Rust accelerating the hot path. The target user is a quantitative researcher who already thinks in pandas and wants parameter sweeps to be an array operation rather than a job queue. The README also names AI agent workflows as a use case, which fits: a matrix-shaped API is easier to generate code against than a stateful strategy class.
How broadcasting turns a parameter grid into a single portfolio call
The mechanism is visible in the README's fourth example. Symbols are downloaded as a multi-symbol frame, then `vbt.MA.run_combs(price, window=windows, r=2, short_names=["fast", "slow"])` produces two moving-average objects spanning every two-window combination from a range. Entries and exits are computed with `ma_crossed_above` and `ma_crossed_below`, and a single call to `vbt.Portfolio.from_signals` runs all of them. The result carries named index levels: the README indexes into it with `pf[(10, 20, "ETH-USD")]` and calls `.stats()` on that slice. Cross-sectional aggregation uses the same levels, as in `pf.total_return().vbt.heatmap(x_level="fast_window", y_level="slow_window", slider_level="symbol")`. So the data flow is: raw price frame, indicator object with a parameter axis, boolean signal arrays broadcast against the price axis, one portfolio object whose index encodes the whole sweep, then groupby or heatmap over the level names. Nothing here is a scheduler or a cluster. The parallelism is array width, and it lives in one process.
Installing it: four extras and what each one pulls in
The base install is `pip install -U vectorbt`. The Rust engine, which the README describes as precompiled speed without JIT overhead, comes from `pip install -U "vectorbt[rust]"`. Optional integrations such as TA-Lib and Pandas TA come from `pip install -U "vectorbt[full]"`, and both together from `pip install -U "vectorbt[full,rust]"`. A Docker image exists at `polakowo/vectorbt`, which is the path of least resistance if you do not want to compile the Rust extension yourself. The README does not state which Python versions the Rust wheel is built for beyond the PyPI badge, so check that badge against your interpreter before assuming the extra installs cleanly. The README also gives `vbt.YFData.download` for market data, with a `missing_index="drop"` argument used in the multi-symbol examples, and `vbt.Portfolio.from_holding` for a buy-and-hold baseline. Configuration in the examples is passed as call arguments rather than a config file: `init_cash`, `size`, `fees`, `freq`. There is no YAML or TOML layer to learn, which is either a relief or a gap depending on how you like to version your experiment settings.
Memory is the constraint that decides whether a sweep is feasible
Vectorised backtesting buys speed by holding everything at once. A 10,000-combination sweep over three symbols means signal arrays and portfolio state with axes for combination, symbol and bar. The README's heatmap example is presented as a single call, and it will be, but the peak resident memory scales with the product of those axes, not with the number of strategies you could have run sequentially. Nothing in the supplied material describes chunking, out-of-core execution or a memory budget, so you should treat the sweep size as something you discover empirically on your own machine. The second constraint is the Rust extra. Without it, the first call into a Numba-compiled function pays JIT compilation cost, which is a one-off per process but noticeable in short scripts and in CI. The third is that vectorisation constrains what a strategy can express. Path-dependent logic that needs the state of the previous trade, or anything that reacts to the portfolio's own equity curve, does not map cleanly onto a broadcast operation. If your strategy needs that, you are fighting the library's core design rather than using it.
The real alternative is an event-driven engine, and the difference is not speed
Backtrader is the obvious comparison point: an event-driven framework where a strategy class receives bars one at a time and can inspect its own broker state at each step. The difference is not that one is faster. It is that Backtrader can express strategies whose next action depends on the current position, the current cash and the sequence of prior fills, because those are all live objects during the walk. VectorBT expresses strategies whose signals can be computed in advance from price and then broadcast across a parameter grid. If your edge is a signal rule, VectorBT's model is a better fit and the sweep is nearly free. If your edge is in execution logic, position sizing that reacts to drawdown, or anything resembling an order lifecycle, an event-driven engine is the honest choice and VectorBT will feel like a straitjacket. The two are not substitutes so much as tools for different halves of the research problem.
Fair Code, the PRO split, and what the badge does not tell you
The licence badge reads Fair Code, and the repository's licence field is NOASSERTION, which means the automated tooling could not classify it. Read LICENSE.md directly rather than relying on the badge. The more consequential fact is in the README's own framing: VectorBT is described as the open-source community edition of VectorBT PRO, a hybrid backtesting library, and the PRO link sits at the top of the page. That means the community edition is a deliberately positioned subset. The README does not enumerate what PRO adds, so anyone evaluating VectorBT for a long-lived project should treat the feature boundary as unknown and find out before building on it. This is not a criticism of the arrangement, which is a common way to fund open source work, but it changes the adoption question from is this library good to is the community edition the version I will still be running in two years.
Maintenance cost and the upgrade path between releases
The release history in the supplied material shows v0.28.5 in March 2026, v1.0.0 in April 2026 and v1.1.0 in July 2026, with the last push to master in early August 2026. A 0.x to 1.0 jump followed by a minor release three months later is a normal cadence for an actively developed library, and it also means the pre-1.0 API you may find in older tutorials is not what you will be writing against. The Rust engine is versioned separately as vectorbt-rust on PyPI, so a `vectorbt[rust]` install couples two release trains; if the Rust wheel lags the Python package for your platform, you are back to the Numba path. Optional integrations pulled in by the `full` extra add their own dependency surface, and TA-Lib in particular has a C library behind it. Budget for reading release notes before each minor bump rather than pinning and forgetting, and check the tests workflow badge on master against the version you plan to install.
Editorial conclusion
Adopt VectorBT if your research loop is grid search over signals on a handful of symbols and you are comfortable reading pandas MultiIndex output. Do not adopt it if you need tick-level or order-book simulation, or if a licence that reserves the heaviest features for a paid PRO edition is a blocker for your team. Before committing, run the 10,000-combination MA example from the README on your own data and check whether the memory footprint and the total runtime fit your machine, then read LICENSE.md in full rather than the badge.
Community notes