vectorbt
High-performance vectorized backtesting with parameter optimization, portfolio simulation, and rich performance metrics
What this skill does
# 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
```bash
uv pip install vectorbt pandas numpy
```
vectorbt pulls in pandas, NumPy, and Plotly automatically. For technical indicators, also install pandas-ta:
```bash
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:
```python
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:
```python
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
```python
# 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:
```python
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
```python
import pandas as pd
# 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
```python
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
```python
# 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
```python
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
```python
# 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
```python
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:
```python
# 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:
```python
# 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%.
```python
# 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% slippRelated in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.