← Back to list
💰

vectorbt Checked

High-performance vectorized backtesting with parameter optimization, portfolio simulation, and ri…
💰 Finance & Trading skills By agiprolabs Version v1.0.0 Added 2026-09-20 Updated 2026-09-20 Source ↗
8.2Overall rating
2Views
5Downloads
366Stars

Installation

🤖 Install via AI

Copy the prompt below and send it to your AI assistant (e.g. Claude Code) — it will follow the instructions and install automatically.

Install the "vectorbt" skill by following the instructions at https://skill123.me/install/vectorbt.
⌨️ Command line install

Run in your terminal — downloads and installs to ~/.claude/skills/.

curl -fsSL https://skill123.me/install/vectorbt.sh | bash
📦 Download ZIP

Download the zip and extract it into your skills directory (e.g. ~/.claude/skills/), then restart your session.

⬇ Download v1.0.0 · 19 KB
📊 Static rating
8.2/10
Trigger
4.0
Structure
9.3
Workflow
8.0
Content
10.0
Engineering
10.0
Security
10.0

Six-dimension rubric with reviewer rationale.

View scorecard ↓
🛡 Dynamic test
—

Not live-tested yet — this skill is rated on static analysis only.

About this skill

High-performance vectorized backtesting with parameter optimization, portfolio simulation, and rich performance metrics

Vectorized Backtesting with vectorbt

Documentation

High-performance vectorized backtesting with parameter optimization, portfolio simulation, and rich performance metrics

Vectorized Backtesting with vectorbt

Overview

vectorbt is a Python library for **vectorized backtesting** — running strategy simulations using NumPy/pandas array operations instead of bar-by-bar loops. This makes it 100–1000x faster than event-driven frameworks (backtrader, zipline), enabling parameter optimization across thousands of combinations in seconds.

**Key strengths:**

  • Blazing speed via NumPy vectorization
  • Built-in parameter grid search and optimization
  • 50+ built-in performance metrics (Sharpe, Sortino, Calmar, max drawdown, profit factor)
  • Rich plotting (equity curves, drawdowns, trade markers, heatmaps)
  • Native pandas integration — your data stays in DataFrames throughout

Installation


uv pip install vectorbt pandas numpy

vectorbt pulls in pandas, NumPy, and Plotly automatically. For technical indicators, also install pandas-ta:


uv pip install vectorbt pandas-ta

Core Concepts

### 1. Signals — Boolean Entry/Exit Arrays

Strategies in vectorbt are expressed as boolean pandas Series (or arrays) indicating where to enter and exit positions:


import vectorbt as vbt
import pandas as pd

# Entry: buy when fast EMA crosses above slow EMA
entries = fast_ema > slow_ema
# Exit: sell when fast EMA crosses below slow EMA
exits = fast_ema < slow_ema

vectorbt resolves conflicting signals automatically (you can't enter while already in a position).

### 2. Portfolio — The Backtesting Engine

vbt.Portfolio.from_signals() is the primary backtesting function. It takes price data and entry/exit signals, simulates trades, and computes performance:


pf = vbt.Portfolio.from_signals(
    close=close_prices,
    entries=entries,
    exits=exits,
    init_cash=10_000,
    fees=0.003,       # 0.3% per trade
    slippage=0.005,   # 0.5% slippage
    freq="1h",        # hourly data
)

### 3. Metrics — Built-in Performance Analysis


# Full stats summary
print(pf.stats())

# Individual metrics
print(f"Total Return: {pf.total_return():.2%}")
print(f"Sharpe Ratio: {pf.sharpe_ratio():.3f}")
print(f"Max Drawdown: {pf.max_drawdown():.2%}")
print(f"Win Rate:     {pf.trades.win_rate():.2%}")

### 4. Parameter Optimization — Grid Search in Seconds

Pass arrays instead of scalars to test many parameter combos simultaneously:


import numpy as np

fast_periods = np.arange(5, 25, 2)   # 10 values
slow_periods = np.arange(20, 60, 5)  # 8 values

fast_ma = vbt.MA.run(close, fast_periods, short_name="fast")
slow_ma = vbt.MA.run(close, slow_periods, short_name="slow")

# This creates 80 parameter combinations automatically
entries = fast_ma.ma_crossed_above(slow_ma)
exits = fast_ma.ma_crossed_below(slow_ma)

Basic Workflow

### Step 1: Load OHLCV Data


import pandas as pd
View full documentation

From CSV

df = pd.read_csv("ohlcv.csv", parse_dates=["timestamp"], index_col="timestamp")

close = df["close"]

From Yahoo Finance (traditional markets)

btc = vbt.YFData.download("BTC-USD", start="2023-01-01", end="2025-01-01")

close = btc.get("Close")



For Solana tokens, fetch data via the `birdeye-api` skill and load into a DataFrame.

### Step 2: Compute Indicators

import pandas_ta as ta

Using pandas-ta (see pandas-ta skill)

df.ta.ema(length=12, append=True)

df.ta.ema(length=26, append=True)

df.ta.rsi(length=14, append=True)

df.ta.bbands(length=20, std=2, append=True)

Or using vectorbt built-ins

rsi = vbt.RSI.run(close, window=14)

bbands = vbt.BBANDS.run(close, window=20, alpha=2)



### Step 3: Generate Entry/Exit Signals

EMA crossover

entries = df["EMA_12"] > df["EMA_26"]

exits = df["EMA_12"] < df["EMA_26"]

RSI mean reversion

entries = rsi.rsi_below(30)

exits = rsi.rsi_above(70)



### Step 4: Run Backtest

pf = vbt.Portfolio.from_signals(

close=close,

entries=entries,

exits=exits,

init_cash=10_000,

fees=0.003,

slippage=0.005,

size=0.95, # use 95% of available cash

size_type="percent",

freq="1h",

)



### Step 5: Analyze Results

Summary statistics

print(pf.stats())

Trade-level analysis

trades = pf.trades.records_readable

print(f"\nTrade count: {len(trades)}")

print(f"Avg holding period: {trades['Duration'].mean()}")

Equity curve

pf.plot().show()

Drawdown chart

pf.drawdowns.plot().show()



## Key Portfolio Parameters

| Parameter | Description | Example |
|-----------|-------------|---------|
| `close` | Price series (pd.Series or DataFrame) | `df["close"]` |
| `entries` | Boolean entry signals | `fast > slow` |
| `exits` | Boolean exit signals | `fast < slow` |
| `init_cash` | Starting capital | `10_000` |
| `fees` | Fee per trade (fraction) | `0.003` (0.3%) |
| `slippage` | Slippage per trade (fraction) | `0.005` (0.5%) |
| `size` | Position size | `0.95` |
| `size_type` | How to interpret size | `"percent"`, `"amount"`, `"value"` |
| `freq` | Data frequency | `"1h"`, `"4h"`, `"1d"` |
| `direction` | Trade direction | `"both"`, `"longonly"`, `"shortonly"` |
| `accumulate` | Allow adding to positions | `False` |
| `sl_stop` | Stop-loss level (fraction) | `0.05` (5%) |
| `tp_stop` | Take-profit level (fraction) | `0.10` (10%) |

## Performance Metrics

### Returns
- `total_return()` — cumulative return over the period
- `annualized_return()` — annualized compound return
- `daily_returns()` — Series of daily returns

### Risk
- `max_drawdown()` — maximum peak-to-trough decline
- `annualized_volatility()` — annualized standard deviation of returns
- `value_at_risk()` — VaR at specified confidence level

### Risk-Adjusted
- `sharpe_ratio()` — excess return per unit volatility
- `sortino_ratio()` — excess return per unit downside deviation
- `calmar_ratio()` — annualized return / max drawdown
- `omega_ratio()` — probability-weighted gain/loss ratio

### Trade Statistics
- `trades.win_rate()` — fraction of profitable trades
- `trades.profit_factor()` — gross profit / gross loss
- `trades.expectancy()` — average P&L per trade
- `trades.avg_winning_trade()` — mean profit on winners
- `trades.avg_losing_trade()` — mean loss on losers
- `trades.count()` — total number of completed trades

## Parameter Optimization

### Grid Search

fast_windows = [5, 8, 12, 15, 20]

slow_windows = [20, 26, 30, 40, 50]

Run all 25 combos at once

fast_ma = vbt.MA.run(close, fast_windows, short_name="fast")

slow_ma = vbt.MA.run(close, slow_windows, short_name="slow")

entries = fast_ma.ma_crossed_above(slow_ma)

exits = fast_ma.ma_crossed_below(slow_ma)

pf = vbt.Portfolio.from_signals(close, entries, exits, fees=0.003)

Find best params by Sharpe

sharpe = pf.sharpe_ratio()

best_idx = sharpe.idxmax()

print(f"Best params: {best_idx}, Sharpe: {sharpe[best_idx]:.3f}")



### Walk-Forward Validation

Always validate optimized parameters on out-of-sample data:

Split: 70% train, 30% test

split_idx = int(len(close) * 0.7)

train_close = close.iloc[:split_idx]

test_close = close.iloc[split_idx:]

Optimize on training data

... (run grid search on train_close)

Validate best params on test data

... (run single backtest on test_close with best params)



See `references/optimization_guide.md` for detailed walk-forward methodology and overfitting prevention.

## Crypto-Specific Considerations

### 24/7 Markets
Crypto markets never close. Use hourly or minute-based frequencies, not business-day frequencies:

Correct for crypto

pf = vbt.Portfolio.from_signals(close, entries, exits, freq="1h")

Wrong — business days assume market closures

pf = vbt.Portfolio.from_signals(close, entries, exits, freq="1B")



### Realistic Fees
DEX swaps on Solana typically cost 0.25–1% including AMM fees. CEX spot fees are 0.05–0.1%.

Solana DEX (conservative)

pf = vbt.Portfolio.from_signals(close, entries, exits, fees=0.005)

CEX spot

pf = vbt.Portfolio.from_signals(close, entries, exits, fees=0.001)



### Slippage
Low-liquidity tokens can have 1–5% slippa

Score breakdown

Trigger
4.0
Description covers What with good keywords (vectorized backtesting, parameter optimization, portfolio simulation) but no When/When-Not or trigger variants: 3+2+3+0=8/20
Structure
9.3
348-line SKILL.md, two references and two scripts, inline load cues, Files section: 4+5+3+2=14/15
Workflow
8.0
Task-oriented 5-step workflow; tool-wrapper pattern with concrete API usage; walk-forward validation guards overfitting; realistic crypto fee/slippage parameters: 5+5+5+3+2=20/25
Content
10.0
Concise imperative, every code block directly runnable with realistic values: 10/10
Engineering
10.0
Valid frontmatter; scripts have shebangs, zero API deps, synthetic data documented; all paths exist: 10/10
Security
10.0
Fully offline scripts; no eval/base64/destructive ops, no secrets, no injection; capabilities match declared scope: 20/20
High-quality vectorbt wrapper skill: 5-step workflow, parameter tables, crypto-realistic fee/slippage guidance, two offline scripts on synthetic data (no API keys), walk-forward validation as an explicit overfitting guard. Capability manifest: no file/env/credential reads, no writes, no network in scripts (Yahoo Finance only mentioned as documentation example), no persistence — capabilities match declared scope.