A vectorbt alternative built on Rust
Updated
Choose Manifold-BT when the result depends on execution (stops, partial fills, funding, size-aware slippage) or on large parameter sweeps; choose vectorbt when you think in pandas and screen vectorized signals. On the same backtest with the same metric suite, Manifold-BT ran 375x faster than vectorbt, 217.2 ms against 81.49 s over 10,000,000 bars, in the public CI run of 2026-11-12, where both engines were installed from PyPI and their results compared before either was timed; the full table is on the benchmarks page. That run measured vectorbt 0.28.4 on its numba path, before the optional Rust backend vectorbt added in 1.0.
Where the two are built differently
vectorbt expresses the whole backtest as operations over NumPy arrays, signals and execution alike. That is extremely fast for signal research and sweeping huge grids of simple rules, and it fits naturally if you already think in pandas.
Manifold-BT evaluates signals the same vectorized way, over the full series in Rust, then runs a sequential pass for fills and PnL. That keeps the speed, years of bars in sub-second, while handling path-dependent logic, stop-losses, take-profits, partial fills, inventory, that is cumbersome to vectorize. It also models execution explicitly: market-impact slippage, funding, and a configurable signal delay.
Side by side
| Manifold-BT | vectorbt | |
|---|---|---|
| Core engine | Rust: vectorized signals + a sequential fills pass (hybrid) | NumPy / Numba, vectorized |
| Speed | 375x faster than vectorbt on the same backtest, metrics included (217.2 ms against 81.49 s over 10,000,000 bars, measured in public CI on 2026-11-12); faster again on GPU for large parameter sweeps | 81.49 s on the same benchmark |
| Path-dependent logic | First-class (stops, partial fills, inventory) | Awkward, often needs manual workarounds |
| Execution realism | Market-impact slippage, funding, partial fills, signal delay | Simplified; costs as flat parameters |
| Parameter search | Parallel sweeps, 2-D heatmaps, walk-forward | Vectorized parameter grids |
| Live trading | No, research only | No, research only |
| API style | Expression DSL, no pandas required | Pandas / NumPy-centric |
| Best for | Realistic, path-dependent research at scale and speed | Quick vectorized signals in a pandas-native API |
What the 375x figure measures
One moving-average crossover, run by both engines over the same 10,000,000 bars with the same metric suite computed at the end, since nobody runs a backtest and then declines to know its Sharpe. Both engines come from PyPI, the same wheels a user installs, on a GitHub-hosted runner. Before anything is timed, the run checks that the two produced the same final equity, the same round trips and the same fees; a workload where they disagree is never quoted as a speedup.
Two limits. The figure was measured against vectorbt 0.28.4 on its numba path, and vectorbt 1.0 has since added an optional Rust backend that this run did not cover. And it is one workload of many: every figure on this page is read from the same run as the benchmarks page and moves with it when a new run is published. That page lists every workload, series length, sweep and memory reading, including the points where the engines diverge and the ones where the gap is much smaller than this one.
The same sweep, with realism intact
Here is a parallel parameter sweep in Manifold-BT. Unlike a vectorized sweep, every combination is evaluated through the full execution engine, so stops and realistic fills apply to each one, with no loss of speed:
import manifoldbt as mbt
from manifoldbt.indicators import close, ema
from manifoldbt.helpers import time_range, Slippage, Interval
fast_p = mbt.param("fast", default=20)
slow_p = mbt.param("slow", default=50)
fast, slow = ema(close, fast_p), ema(close, slow_p)
strategy = (
mbt.Strategy.create("ema")
.signal("fast", fast)
.signal("slow", slow)
.size(mbt.when(fast > slow, 1.0, 0.0))
)
start, end = time_range("2021-01-01", "2026-01-01")
config = mbt.BacktestConfig(
universe={"binance": ["BTCUSDT"]},
time_range_start=start,
time_range_end=end,
bar_interval=Interval.hours(1),
initial_capital=10_000,
fees=mbt.FeeConfig.binance_perps(),
slippage=Slippage.fixed_bps(2),
warmup_bars=50,
)
store = mbt.ingest(provider="binance", symbol="BTCUSDT", symbol_id=1,
interval="1h", start="2021-01-01T00:00:00Z",
end="2026-01-01T00:00:00Z")
# Sweep the whole grid in parallel on Rust, with stops and realistic fills intact
sweep = mbt.run_sweep(
strategy,
param_grid={"fast": [10, 20, 30], "slow": [50, 100, 150]},
config=config,
store=store,
)
print(sweep.best("sharpe"))Is the DSL heavier than vectorbt?
A fair worry: the pandas-native API of vectorbt is famously terse, so a dedicated DSL can sound like more to learn. In practice it is not heavier, just explicit. The same long-only crossover is a handful of lines in both, and the Manifold-BT version reads top to bottom, signal then sizing, with no pandas accessors or array plumbing to wire up.
import vectorbt as vbt
price = vbt.YFData.download("BTC-USD").get("Close")
fast = vbt.MA.run(price, 20)
slow = vbt.MA.run(price, 50)
entries = fast.ma_crossed_above(slow)
exits = fast.ma_crossed_below(slow)
pf = vbt.Portfolio.from_signals(price, entries, exits, fees=0.001)import manifoldbt as mbt
from manifoldbt.indicators import close, ema
fast, slow = ema(close, 20), ema(close, 50)
strategy = (
mbt.Strategy.create("ema_cross")
.signal("fast", fast)
.signal("slow", slow)
.size(mbt.when(fast > slow, 1.0, 0.0))
)
result = mbt.run(strategy, config, store)The gap opens the moment you add path-dependent logic. A stop-loss or a take-profit is one chained call in Manifold-BT, for example .stop_loss(pct=3.0), whereas a vectorized engine usually means leaving the fast path and hand-rolling the exit. You keep the concise style and still get realistic, path-dependent execution.
Which should you pick?
Choose Manifold-BT if you want the backtest to match the fill: an explicit execution model, stops, partial fills, funding on crypto perpetuals, and size-aware slippage, path-dependent logic that never leaves the fast path, and large parameter sweeps and walk-forward that finish in seconds, including on GPU. For systematic research where execution and costs decide the edge, that is the tool. vectorbt stays a fair pick only if you already live in its pandas ecosystem and your work is purely vectorized, cross-sectional signal research.
Frequently asked questions
Is Manifold-BT a drop-in replacement for vectorbt?
No. The API is different: a Manifold-BT strategy is declared as expressions in a Python DSL (signals, then sizing), not as pandas arrays passed to Portfolio.from_signals, so moving a strategy over means rewriting its definition. For a crossover that is a handful of lines, as the side-by-side code on this page shows. If you want to keep vectorbt's API and swap the engine underneath, RaptorBT is the project built as a drop-in vectorbt replacement; Manifold-BT vs RaptorBT is compared on its own page.
Which is faster, Manifold-BT or vectorbt?
On the public CI run of 2026-11-12, Manifold-BT: 217.2 ms against 81.49 s for the same backtest with the same metric suite over 10,000,000 bars, 375x faster. Both engines were installed from PyPI on a GitHub-hosted runner and their final equity, round trips and fees were compared before anything was timed. The run measured vectorbt 0.28.4 on its numba path; vectorbt 1.0 added an optional Rust backend, which has not been measured here yet. Parameter sweeps, cold start and memory are on the benchmarks page, which shows the same run.
Does vectorbt model slippage and funding?
Slippage, yes; funding, not as a built-in. In the open-source version's order model, fees are a percentage of order value plus an optional fixed fee per order, slippage is a penalty applied to the price, and an order larger than max_size is partly filled. There is no funding-rate or borrow-cost field, so carry on perpetuals or shorts has to be added by hand. Manifold-BT applies perpetual funding per bar from a funding-rate column in your data, charges borrow on shorts in annualised basis points, offers fixed, spread-based and volume-impact slippage, and caps fills at a share of each bar's volume.
Can vectorbt handle stops and path-dependent logic?
Yes. from_signals supports stop-loss and take-profit exits, and order functions with numba callbacks can express most path-dependent rules. The fair criticism is that the second route is awkward and thinly documented. In Manifold-BT a stop or a target is one chained call on the strategy, applied by the sequential fills pass.
Is Manifold-BT free? Is vectorbt?
Both have a free version. Manifold-BT's Community tier runs the full-speed engine, including for commercial use, with sweeps capped at 256 backtests, daily output resolution and 1,000 Monte Carlo simulations; the Python package is Apache 2.0 and the engine ships as a compiled wheel under the Manifold-BT Engine License. Pro, at $16/mo billed annually, or $19 month to month, lifts those caps and adds walk-forward. vectorbt is source-available under Apache 2.0 with a Commons Clause, which forbids selling a product built on it; vectorbt PRO is a separate membership at $25 a month, $240 a year or $500 for life, for personal use.
Does either one trade live?
No. Both are research tools and neither places orders. The usual workflow is to find and validate the strategy in one of them, then deploy it on a platform built for execution, such as NautilusTrader or a broker API.
Keep reading
Run your first backtest
Install Manifold-BT and reproduce the backtest above in seconds. The Rust core runs years of bars sub-second so you can sweep parameters instead of waiting.