agiprolabs/claude-trading-skills5 files

Vectorbt

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

Specification
Skill ID
agiprolabs/claude-trading-skills/vectorbt
Publisher
agiprolabs
Repository
claude-trading-skills
Installs
0
Files
5
Synced
Sep 23, 2026
How to use it

Open any RiverX project, open the Skills panel in the chat, and search for this identifier. The files are fetched from the source repository at install time.

agiprolabs/claude-trading-skills/vectorbtInstalls these files
  • SKILL.md
  • references/api_guide.md
  • references/optimization_guide.md
  • scripts/backtest_example.py
  • scripts/parameter_sweep.py

What this skill tells the agent

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

# 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

ParameterDescriptionExample
closePrice series (pd.Series or DataFrame)df["close"]
entriesBoolean entry signalsfast > slow
exitsBoolean exit signalsfast < slow
init_cashStarting capital10_000
feesFee per trade (fraction)0.003 (0.3%)
slippageSlippage per trade (fraction)0.005 (0.5%)
sizePosition size0.95
size_typeHow to interpret size"percent", "amount", "value"
freqData frequency"1h", "4h", "1d"
directionTrade direction"both", "longonly", "shortonly"
accumulateAllow adding to positionsFalse
sl_stopStop-loss level (fraction)0.05 (5%)
tp_stopTake-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

Use this skill in a project

Open any RiverX project, search the Skills panel for agiprolabs/claude-trading-skills/vectorbt, and install it in one click.

Use this skill