vectorbt

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Vectorized Backtesting with vectorbt

使用 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
vectorbt 是一个用于向量化回测的 Python 库——它使用 NumPy/pandas 数组操作来运行策略模拟,而不是逐根 K 线循环。这使它比事件驱动框架(backtrader、zipline)快 100–1000 倍,并能在数秒内完成数千种参数组合的优化。
主要优势:
  • 通过 NumPy 向量化实现极高性能
  • 内置参数网格搜索和优化
  • 内置 50 多种绩效指标(Sharpe、Sortino、Calmar、最大回撤、盈利因子)
  • 丰富的绘图功能(净值曲线、回撤、交易标记、热力图)
  • 原生集成 pandas——数据在整个流程中始终保留为 DataFrame

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
bash
uv pip install vectorbt pandas numpy
vectorbt 会自动安装 pandas、NumPy 和 Plotly。如需技术指标,还需安装 pandas-ta:
bash
uv pip install vectorbt pandas-ta

Core Concepts

核心概念

1. Signals — Boolean Entry/Exit Arrays

1. 信号——布尔型入场/退出数组

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
vectorbt 中的策略表示为布尔型 pandas Series(或数组),用于指示何时入场和退出仓位:
python
import vectorbt as vbt
import pandas as pd

Entry: buy when fast EMA crosses above slow EMA

Entry: buy when fast EMA crosses above slow EMA

entries = fast_ema > slow_ema
entries = fast_ema > slow_ema

Exit: sell when fast EMA crosses below 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).
exits = fast_ema < slow_ema

vectorbt 会自动解决冲突信号(持有仓位时无法再次入场)。

2. Portfolio — The Backtesting Engine

2. 投资组合——回测引擎

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
)
vbt.Portfolio.from_signals()
是主要的回测函数。它接受价格数据和入场/退出信号,模拟交易并计算绩效:
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

3. 指标——内置绩效分析

python
undefined
python
undefined

Full stats summary

Full stats summary

print(pf.stats())
print(pf.stats())

Individual metrics

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%}")
undefined
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%}")
undefined

4. Parameter Optimization — Grid Search in Seconds

4. 参数优化——数秒完成网格搜索

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")
传入数组而非标量,可以同时测试多组参数组合:
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

This creates 80 parameter combinations automatically

entries = fast_ma.ma_crossed_above(slow_ma) exits = fast_ma.ma_crossed_below(slow_ma)
undefined
entries = fast_ma.ma_crossed_above(slow_ma) exits = fast_ma.ma_crossed_below(slow_ma)
undefined

Basic Workflow

基本工作流

Step 1: Load OHLCV Data

第 1 步:加载 OHLCV 数据

python
import pandas as pd
python
import pandas as pd

From CSV

From CSV

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

From Yahoo Finance (traditional markets)

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.
btc = vbt.YFData.download("BTC-USD", start="2023-01-01", end="2025-01-01") close = btc.get("Close")

对于 Solana 代币,可通过 `birdeye-api` skill 获取数据并加载到 DataFrame 中。

Step 2: Compute Indicators

第 2 步:计算指标

python
import pandas_ta as ta
python
import pandas_ta as ta

Using pandas-ta (see pandas-ta skill)

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)
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

Or using vectorbt built-ins

rsi = vbt.RSI.run(close, window=14) bbands = vbt.BBANDS.run(close, window=20, alpha=2)
undefined
rsi = vbt.RSI.run(close, window=14) bbands = vbt.BBANDS.run(close, window=20, alpha=2)
undefined

Step 3: Generate Entry/Exit Signals

第 3 步:生成入场/退出信号

python
undefined
python
undefined

EMA crossover

EMA crossover

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

RSI mean reversion

RSI mean reversion

entries = rsi.rsi_below(30) exits = rsi.rsi_above(70)
undefined
entries = rsi.rsi_below(30) exits = rsi.rsi_above(70)
undefined

Step 4: Run Backtest

第 4 步:运行回测

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",
)
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

第 5 步:分析结果

python
undefined
python
undefined

Summary statistics

Summary statistics

print(pf.stats())
print(pf.stats())

Trade-level analysis

Trade-level analysis

trades = pf.trades.records_readable print(f"\nTrade count: {len(trades)}") print(f"Avg holding period: {trades['Duration'].mean()}")
trades = pf.trades.records_readable print(f"\nTrade count: {len(trades)}") print(f"Avg holding period: {trades['Duration'].mean()}")

Equity curve

Equity curve

pf.plot().show()
pf.plot().show()

Drawdown chart

Drawdown chart

pf.drawdowns.plot().show()
undefined
pf.drawdowns.plot().show()
undefined

Key Portfolio Parameters

投资组合关键参数

ParameterDescriptionExample
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%)
参数说明示例
close
价格序列(pd.Series 或 DataFrame)
df["close"]
entries
布尔型入场信号
fast > slow
exits
布尔型退出信号
fast < slow
init_cash
初始资金
10_000
fees
每笔交易的手续费(比例)
0.003
(0.3%)
slippage
每笔交易的滑点(比例)
0.005
(0.5%)
size
仓位规模
0.95
size_type
size 的解释方式
"percent"
、
"amount"
、
"value"
freq
数据频率
"1h"
、
"4h"
、
"1d"
direction
交易方向
"both"
、
"longonly"
、
"shortonly"
accumulate
允许增加仓位
False
sl_stop
止损水平(比例)
0.05
(5%)
tp_stop
止盈水平(比例)
0.10
(10%)

Performance Metrics

绩效指标

Returns

收益率

  • total_return()
    — cumulative return over the period
  • annualized_return()
    — annualized compound return
  • daily_returns()
    — Series of daily returns
  • total_return()
    — 期间累计收益率
  • annualized_return()
    — 年化复合收益率
  • 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
  • max_drawdown()
    — 从峰值到谷底的最大跌幅
  • annualized_volatility()
    — 收益率的年化标准差
  • value_at_risk()
    — 指定置信水平下的 VaR

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
  • sharpe_ratio()
    — 单位波动率对应的超额收益
  • sortino_ratio()
    — 单位下行偏差对应的超额收益
  • calmar_ratio()
    — 年化收益率 / 最大回撤
  • omega_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
  • trades.win_rate()
    — 盈利交易占比
  • trades.profit_factor()
    — 总利润 / 总亏损
  • trades.expectancy()
    — 每笔交易的平均损益
  • trades.avg_winning_trade()
    — 盈利交易的平均利润
  • trades.avg_losing_trade()
    — 亏损交易的平均损失
  • trades.count()
    — 已完成交易总数

Parameter Optimization

参数优化

Grid Search

网格搜索

python
fast_windows = [5, 8, 12, 15, 20]
slow_windows = [20, 26, 30, 40, 50]
python
fast_windows = [5, 8, 12, 15, 20]
slow_windows = [20, 26, 30, 40, 50]

Run all 25 combos at once

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)
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

Find best params by Sharpe

sharpe = pf.sharpe_ratio() best_idx = sharpe.idxmax() print(f"Best params: {best_idx}, Sharpe: {sharpe[best_idx]:.3f}")
undefined
sharpe = pf.sharpe_ratio() best_idx = sharpe.idxmax() print(f"Best params: {best_idx}, Sharpe: {sharpe[best_idx]:.3f}")
undefined

Walk-Forward Validation

滚动前向验证

Always validate optimized parameters on out-of-sample data:
python
undefined
始终在样本外数据上验证优化后的参数:
python
undefined

Split: 70% train, 30% test

Split: 70% train, 30% test

split_idx = int(len(close) * 0.7) train_close = close.iloc[:split_idx] test_close = close.iloc[split_idx:]
split_idx = int(len(close) * 0.7) train_close = close.iloc[:split_idx] test_close = close.iloc[split_idx:]

Optimize on training data

Optimize on training data

... (run grid search on train_close)

... (run grid search on train_close)

Validate best params on test data

Validate best params on test data

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

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


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

有关详细的 Walk-Forward 方法和防止过拟合的信息,请参阅 `references/optimization_guide.md`。

Crypto-Specific Considerations

加密货币特有的注意事项

24/7 Markets

24/7 市场

Crypto markets never close. Use hourly or minute-based frequencies, not business-day frequencies:
python
undefined
加密货币市场从不休市。应使用小时级或分钟级频率,而不是工作日频率:
python
undefined

Correct for crypto

Correct for crypto

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

Wrong — business days assume market closures

Wrong — business days assume market closures

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

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

undefined
undefined

Realistic Fees

实际费用

DEX swaps on Solana typically cost 0.25–1% including AMM fees. CEX spot fees are 0.05–0.1%.
python
undefined
Solana 上的 DEX swap 通常成本为 0.25–1%(包括 AMM 费用)。CEX 现货手续费为 0.05–0.1%。
python
undefined

Solana DEX (conservative)

Solana DEX (conservative)

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

CEX spot

CEX spot

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

Slippage

滑点

Low-liquidity tokens can have 1–5% slippage. Always model this:
python
undefined
低流动性代币可能产生 1–5% 的滑点。务必对其进行建模:
python
undefined

High-liquidity (SOL, ETH): 0.1–0.5%

High-liquidity (SOL, ETH): 0.1–0.5%

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

Low-liquidity memecoins: 1–3%

Low-liquidity memecoins: 1–3%

pf = vbt.Portfolio.from_signals(close, entries, exits, slippage=0.02)
undefined
pf = vbt.Portfolio.from_signals(close, entries, exits, slippage=0.02)
undefined

Short History

历史数据较短

Many tokens have less than 1 year of data. Be cautious about annualizing metrics from short samples.
许多代币的数据不足 1 年。对于短样本下的年化指标应谨慎解读。

Common Strategy Patterns

常见策略模式

EMA Crossover

EMA 交叉策略

python
fast = vbt.MA.run(close, 12, short_name="fast")
slow = vbt.MA.run(close, 26, short_name="slow")
entries = fast.ma_crossed_above(slow)
exits = fast.ma_crossed_below(slow)
python
fast = vbt.MA.run(close, 12, short_name="fast")
slow = vbt.MA.run(close, 26, short_name="slow")
entries = fast.ma_crossed_above(slow)
exits = fast.ma_crossed_below(slow)

RSI Mean Reversion

RSI 均值回归

python
rsi = vbt.RSI.run(close, 14)
entries = rsi.rsi_crossed_below(30)
exits = rsi.rsi_crossed_above(70)
python
rsi = vbt.RSI.run(close, 14)
entries = rsi.rsi_crossed_below(30)
exits = rsi.rsi_crossed_above(70)

Bollinger Band Breakout

布林带突破

python
bb = vbt.BBANDS.run(close, window=20, alpha=2)
entries = close > bb.upper
exits = close < bb.lower
python
bb = vbt.BBANDS.run(close, window=20, alpha=2)
entries = close > bb.upper
exits = close < bb.lower

Stop-Loss and Take-Profit

止损与止盈

python
pf = vbt.Portfolio.from_signals(
    close, entries, exits,
    sl_stop=0.05,    # 5% stop-loss
    tp_stop=0.10,    # 10% take-profit
)
python
pf = vbt.Portfolio.from_signals(
    close, entries, exits,
    sl_stop=0.05,    # 5% stop-loss
    tp_stop=0.10,    # 10% take-profit
)

Related Skills

相关 Skill

  • pandas-ta — Technical indicator computation (feeds vectorbt signals)
  • birdeye-api — Fetch Solana token OHLCV data for backtesting
  • trading-visualization — Advanced chart generation for backtest results
  • portfolio-analytics — Deeper portfolio-level risk/return analysis
  • position-sizing — Optimal position sizing methodology
  • risk-management — Portfolio-level risk guardrails
  • regime-detection — Market regime awareness for adaptive strategies
  • pandas-ta — 技术指标计算(为 vectorbt 提供信号)
  • birdeye-api — 获取用于回测的 Solana 代币 OHLCV 数据
  • trading-visualization — 为回测结果生成高级图表
  • portfolio-analytics — 更深入的投资组合级风险/收益分析
  • position-sizing — 最佳仓位规模管理方法
  • risk-management — 投资组合级风险护栏
  • regime-detection — 面向自适应策略的市场状态识别

Files

文件

References

参考资料

  • references/api_guide.md
    — Complete vectorbt API reference for Portfolio, indicators, plotting, and data loading
  • references/optimization_guide.md
    — Grid search, walk-forward validation, overfitting prevention, and optimization best practices
  • references/api_guide.md
    — Portfolio、指标、绘图和数据加载的完整 vectorbt API 参考
  • references/optimization_guide.md
    — 网格搜索、Walk-Forward 验证、防止过拟合和优化最佳实践

Scripts

脚本

  • scripts/backtest_example.py
    — Three-strategy backtest comparison using synthetic data (EMA crossover, RSI mean reversion, Bollinger breakout)
  • scripts/parameter_sweep.py
    — EMA crossover parameter grid search with walk-forward validation
  • scripts/backtest_example.py
    — 使用合成数据的三策略回测比较(EMA 交叉、RSI 均值回归、布林带突破)
  • scripts/parameter_sweep.py
    — 带 Walk-Forward 验证的 EMA 交叉参数网格搜索