Getting Started with VectorBT
Welcome to VectorBT - the most powerful backtesting framework for Indian stock markets. This module will take you from zero to your first profitable strategy on NSE stocks.
What You'll Learn
- Install and configure VectorBT
- Download NSE/BSE stock data
- Create your first strategy
- Analyze performance metrics
Prerequisites
- Python 3.8 or higher
- Basic Python knowledge
- Understanding of stock markets
- Jupyter Notebook (optional)
Why VectorBT?
Lightning Fast Performance
Test thousands of parameter combinations on entire NIFTY 50 in seconds, not hours.
Comprehensive Metrics
Get 50+ performance metrics including Sharpe ratio, maximum drawdown, and Indian market-specific calculations.
Pythonic & Intuitive
Works seamlessly with pandas, NumPy, and other data science libraries you already know.
Installation & Setup
Step 1: Create Virtual Environment
It's recommended to use a virtual environment to avoid package conflicts:
# Create virtual environment
python -m venv vbt_env
# Activate on Windows
vbt_env\Scripts\activate
# Activate on Mac/Linux
source vbt_env/bin/activate
Step 2: Install VectorBT
Install VectorBT with all optional dependencies for full functionality:
# Install VectorBT with all features
pip install vectorbt[full]
# Or install specific components
pip install vectorbt # Core library
pip install vectorbt[data] # Data download features
pip install vectorbt[plotting] # Visualization features
Step 3: Install Indian Market Libraries
Additional libraries for working with Indian stock data:
# Yahoo Finance for NSE/BSE data
pip install yfinance
# NSEPy for NSE specific data
pip install nsepy
# Technical indicators
pip install ta-lib # Requires C++ libraries
pip install pandas-ta # Pure Python alternative
# Visualization
pip install plotly
pip install matplotlib
Pro Tip
If you face issues installing TA-Lib on Windows, download the pre-compiled wheel from here and install using pip.
Step 4: Verify Installation
import vectorbt as vbt
import pandas as pd
import numpy as np
import yfinance as yf
print(f"VectorBT version: {vbt.__version__}")
print(f"Pandas version: {pd.__version__}")
print(f"NumPy version: {np.__version__}")
print("Installation successful! 🎉")
Indian Market Data Sources
Yahoo Finance (Recommended)
Yahoo Finance provides free historical data for NSE and BSE stocks. Add '.NS' for NSE and '.BO' for BSE:
import vectorbt as vbt
# Download single stock
reliance = vbt.YFData.download(
"RELIANCE.NS",
start="2023-01-01",
end="2024-01-01"
)
# Download multiple stocks
stocks = ["RELIANCE.NS", "TCS.NS", "HDFCBANK.NS", "INFY.NS"]
data = vbt.YFData.download(
stocks,
start="2023-01-01",
end="2024-01-01"
)
# Download index data
nifty = vbt.YFData.download(
"^NSEI", # NIFTY 50
start="2023-01-01",
end="2024-01-01"
)
# Bank NIFTY
bank_nifty = vbt.YFData.download(
"^NSEBANK",
start="2023-01-01",
end="2024-01-01"
)
NSEPy Library
NSEPy provides more detailed NSE data including F&O chain:
from nsepy import get_history
from datetime import date
# Get stock data
sbin = get_history(
symbol="SBIN",
start=date(2023,1,1),
end=date(2024,1,1)
)
# Get index data
nifty = get_history(
symbol="NIFTY",
start=date(2023,1,1),
end=date(2024,1,1),
index=True
)
# Get F&O data
sbin_fut = get_history(
symbol="SBIN",
start=date(2023,1,1),
end=date(2024,1,1),
futures=True,
expiry_date=date(2024,1,25)
)
Data Quality Note
Always verify data quality, especially for splits and bonuses. Indian stocks often have corporate actions that may not be properly adjusted in free data sources.
Loading Data from CSV Files
You can also load historical data from CSV files stored locally:
import pandas as pd
import vectorbt as vbt
# Load data from CSV file
# Sample data available in data/samples/ folder
reliance_df = pd.read_csv('data/samples/RELIANCE_sample.csv',
parse_dates=['Date'],
index_col='Date')
# Convert to VectorBT format
data = vbt.Data.from_data(reliance_df)
close = data.get('Close')
# Load NIFTY index data
nifty_df = pd.read_csv('data/indices/NIFTY.csv',
parse_dates=['DATE'],
index_col='DATE')
# Load multiple stocks data
stocks_info = pd.read_csv('data/samples/sample_stocks.csv')
print(f"Available stocks: {stocks_info['Symbol'].tolist()}")
# For intraday data with date and time
intraday_df = pd.read_csv('data/indices/NIFTY.csv')
intraday_df['DATETIME'] = pd.to_datetime(intraday_df['DATE'] + ' ' + intraday_df['TIME'])
intraday_df.set_index('DATETIME', inplace=True)
Common NSE/BSE Symbols
Indices
^NSEI- NIFTY 50^NSEBANK- Bank NIFTY^NSMIDCP- NIFTY Midcap^BSESN- SENSEX
Top Stocks
RELIANCE.NS- Reliance IndustriesTCS.NS- Tata Consultancy ServicesHDFCBANK.NS- HDFC BankINFY.NS- Infosys
Your First Backtest
Let's create a simple moving average crossover strategy on RELIANCE:
Complete Code Example
import vectorbt as vbt
import pandas as pd
import numpy as np
# Step 1: Download RELIANCE data
print("Downloading RELIANCE data...")
data = vbt.YFData.download(
"RELIANCE.NS",
start="2022-01-01",
end="2024-01-01",
missing_index='drop' # Remove any missing data
)
# Get the closing prices
close = data.get('Close')
print(f"Data shape: {close.shape}")
print(f"Date range: {close.index[0]} to {close.index[-1]}")
# Step 2: Calculate Moving Averages
fast_ma = vbt.MA.run(close, window=10, short_name='SMA_10')
slow_ma = vbt.MA.run(close, window=30, short_name='SMA_30')
# Step 3: Generate Trading Signals
entries = fast_ma.ma_crossed_above(slow_ma) # Buy signal
exits = fast_ma.ma_crossed_below(slow_ma) # Sell signal
print(f"Total buy signals: {entries.sum()}")
print(f"Total sell signals: {exits.sum()}")
# Step 4: Run Backtest
portfolio = vbt.Portfolio.from_signals(
close,
entries,
exits,
init_cash=10_00_000, # ₹10 Lakhs initial capital
fees=0.0003, # 0.03% transaction cost (typical for Indian markets)
slippage=0.0005, # 0.05% slippage
freq='1D' # Daily frequency
)
# Step 5: View Results
print("\n" + "="*50)
print("BACKTEST RESULTS")
print("="*50)
print(portfolio.stats())
# Key Metrics
print("\n" + "="*50)
print("KEY PERFORMANCE METRICS")
print("="*50)
print(f"Total Return: {portfolio.total_return():.2%}")
print(f"Annual Return: {portfolio.annualized_return():.2%}")
print(f"Sharpe Ratio: {portfolio.sharpe_ratio():.2f}")
print(f"Max Drawdown: {portfolio.max_drawdown():.2%}")
print(f"Win Rate: {portfolio.trades.win_rate():.2%}")
print(f"Total Trades: {portfolio.trades.count()}")
Understanding the Results
Positive Indicators
- ✅ Positive total return
- ✅ Sharpe ratio > 1.0
- ✅ Win rate > 50%
- ✅ Low maximum drawdown < 20%
Warning Signs
- ❌ Negative returns
- ❌ Sharpe ratio < 0.5
- ❌ Very few trades (< 10)
- ❌ High drawdown > 30%
NIFTY 50 Portfolio Example
Let's create a momentum strategy on top NIFTY 50 stocks:
# Top 10 NIFTY 50 stocks by weight
nifty_stocks = [
"RELIANCE.NS", "HDFCBANK.NS", "INFY.NS", "ICICIBANK.NS",
"TCS.NS", "KOTAKBANK.NS", "LT.NS", "HINDUNILVR.NS",
"AXISBANK.NS", "ITC.NS"
]
# Download data for all stocks
print("Downloading NIFTY 50 stocks data...")
data = vbt.YFData.download(
nifty_stocks,
start="2022-01-01",
end="2024-01-01",
missing_index='drop'
)
close = data.get('Close')
# Calculate 20-day momentum (Rate of Change)
roc = vbt.ROC.run(close, window=20)
# Rank stocks by momentum
def get_top_stocks(roc_values, n=3):
"""Select top N stocks by momentum"""
rankings = roc_values.rank(axis=1, ascending=False)
return rankings <= n
# Generate signals: Buy top 3 momentum stocks
entries = get_top_stocks(roc.roc, n=3)
# Hold for 20 days
exits = entries.shift(20).fillna(False)
# Run backtest with equal weights
portfolio = vbt.Portfolio.from_signals(
close,
entries,
exits,
init_cash=50_00_000, # ₹50 Lakhs
fees=0.0003,
slippage=0.0005,
freq='1D',
group_by=True, # Treat as single portfolio
cash_sharing=True, # Share cash between assets
size=1/3, # Equal weight (1/3 for each of 3 stocks)
size_type='targetpercent'
)
# Results
print("\nNIFTY 50 Momentum Strategy Results:")
print("="*50)
print(f"Total Return: {portfolio.total_return():.2%}")
print(f"Annual Return: {portfolio.annualized_return():.2%}")
print(f"Sharpe Ratio: {portfolio.sharpe_ratio():.2f}")
print(f"Max Drawdown: {portfolio.max_drawdown():.2%}")
# Compare with buy-and-hold NIFTY
nifty_index = vbt.YFData.download("^NSEI", start="2022-01-01", end="2024-01-01")
nifty_return = (nifty_index.get('Close').iloc[-1] / nifty_index.get('Close').iloc[0] - 1)
print(f"\nNIFTY 50 Buy & Hold Return: {nifty_return:.2%}")
print(f"Strategy Alpha: {portfolio.total_return() - nifty_return:.2%}")
Understanding Performance Metrics
Essential Metrics for Indian Markets
Returns Metrics
- Total Return
- Overall profit/loss percentage
- CAGR
- Compound Annual Growth Rate
- Annualized Return
- Yearly return normalized
Risk Metrics
- Sharpe Ratio
- Risk-adjusted returns (> 1 is good)
- Max Drawdown
- Largest peak-to-trough decline
- Volatility
- Standard deviation of returns
Accessing All Metrics
# Get all statistics
stats = portfolio.stats()
print(stats)
# Access specific metrics
print(f"Total Return: {portfolio.total_return():.2%}")
print(f"Sharpe Ratio: {portfolio.sharpe_ratio():.2f}")
print(f"Sortino Ratio: {portfolio.sortino_ratio():.2f}")
print(f"Calmar Ratio: {portfolio.calmar_ratio():.2f}")
print(f"Max Drawdown: {portfolio.max_drawdown():.2%}")
print(f"Annual Volatility: {portfolio.annualized_volatility():.2%}")
# Trade statistics
trades = portfolio.trades.records_readable
print(f"\nTotal Trades: {len(trades)}")
print(f"Win Rate: {portfolio.trades.win_rate():.2%}")
print(f"Average Win: {portfolio.trades.avg_winning_trade():.2%}")
print(f"Average Loss: {portfolio.trades.avg_losing_trade():.2%}")
print(f"Profit Factor: {portfolio.trades.profit_factor():.2f}")
# Custom metric for Indian markets (considering STT)
stt_cost = len(trades) * 0.001 * portfolio.value().iloc[-1] # 0.1% STT
net_return = portfolio.total_return() - (stt_cost / portfolio.init_cash)
print(f"\nReturn after STT: {net_return:.2%}")
Visualization & Analysis
Interactive Plots
# 1. Complete portfolio plot
fig = portfolio.plot()
fig.show()
# 2. Individual component plots
# Cumulative returns
portfolio.plot_cumulative_returns().show()
# Drawdown
portfolio.plot_drawdowns().show()
# Underwater plot (time spent in drawdown)
portfolio.plot_underwater().show()
# 3. Trade analysis
portfolio.trades.plot().show()
portfolio.trades.plot_pnl().show()
# 4. Custom plot with entry/exit points
import plotly.graph_objects as go
fig = go.Figure()
# Add price line
fig.add_trace(go.Scatter(
x=close.index,
y=close.values,
mode='lines',
name='Price',
line=dict(color='blue', width=1)
))
# Add entry points
entry_points = close[entries]
fig.add_trace(go.Scatter(
x=entry_points.index,
y=entry_points.values,
mode='markers',
name='Buy',
marker=dict(
color='green',
size=10,
symbol='triangle-up'
)
))
# Add exit points
exit_points = close[exits]
fig.add_trace(go.Scatter(
x=exit_points.index,
y=exit_points.values,
mode='markers',
name='Sell',
marker=dict(
color='red',
size=10,
symbol='triangle-down'
)
))
# Add moving averages
fig.add_trace(go.Scatter(
x=close.index,
y=fast_ma.ma.values,
mode='lines',
name='Fast MA (10)',
line=dict(color='orange', width=1, dash='dash')
))
fig.add_trace(go.Scatter(
x=close.index,
y=slow_ma.ma.values,
mode='lines',
name='Slow MA (30)',
line=dict(color='purple', width=1, dash='dash')
))
fig.update_layout(
title='RELIANCE Trading Strategy',
xaxis_title='Date',
yaxis_title='Price (₹)',
hovermode='x unified',
template='plotly_white'
)
fig.show()
Performance Dashboard
# Create a comprehensive dashboard
from plotly.subplots import make_subplots
fig = make_subplots(
rows=3, cols=2,
subplot_titles=(
'Cumulative Returns', 'Drawdown',
'Monthly Returns', 'Trade Distribution',
'Rolling Sharpe', 'Volume'
),
vertical_spacing=0.1,
horizontal_spacing=0.1
)
# Cumulative returns
cum_returns = portfolio.cumulative_returns()
fig.add_trace(
go.Scatter(x=cum_returns.index, y=cum_returns.values, name='Returns'),
row=1, col=1
)
# Drawdown
drawdown = portfolio.drawdown()
fig.add_trace(
go.Scatter(x=drawdown.index, y=drawdown.values, name='Drawdown', fill='tozeroy'),
row=1, col=2
)
# Monthly returns heatmap
monthly_returns = portfolio.resample_returns('M')
fig.add_trace(
go.Bar(x=monthly_returns.index, y=monthly_returns.values, name='Monthly'),
row=2, col=1
)
# Trade PnL distribution
trade_returns = portfolio.trades.returns
fig.add_trace(
go.Histogram(x=trade_returns, name='Trade Returns', nbinsx=20),
row=2, col=2
)
# Rolling Sharpe (252 days)
rolling_sharpe = portfolio.rolling_sharpe(window=252)
fig.add_trace(
go.Scatter(x=rolling_sharpe.index, y=rolling_sharpe.values, name='Sharpe'),
row=3, col=1
)
# Volume
volume = data.get('Volume')
fig.add_trace(
go.Bar(x=volume.index, y=volume.values, name='Volume'),
row=3, col=2
)
fig.update_layout(height=900, showlegend=False)
fig.show()
Practice Exercises
Exercise 1: RSI Strategy on TCS
Create an RSI-based strategy on TCS.NS with the following rules:
- • Buy when RSI(14) crosses below 30
- • Sell when RSI(14) crosses above 70
- • Use ₹5 Lakhs capital
- • Compare with buy-and-hold returns
Show Solution
# Solution
data = vbt.YFData.download("TCS.NS", start="2022-01-01", end="2024-01-01")
close = data.get('Close')
# Calculate RSI
rsi = vbt.RSI.run(close, window=14)
# Generate signals
entries = rsi.rsi_crossed_below(30)
exits = rsi.rsi_crossed_above(70)
# Backtest
portfolio = vbt.Portfolio.from_signals(
close, entries, exits,
init_cash=5_00_000,
fees=0.0003
)
print(f"Strategy Return: {portfolio.total_return():.2%}")
bh_return = (close.iloc[-1] / close.iloc[0] - 1)
print(f"Buy & Hold Return: {bh_return:.2%}")
print(f"Alpha: {portfolio.total_return() - bh_return:.2%}")
Exercise 2: Bank NIFTY Bollinger Bands
Implement a Bollinger Bands strategy on Bank NIFTY:
- • Buy when price touches lower band
- • Sell when price touches upper band
- • Use 20-period SMA and 2 standard deviations
- • Calculate Sharpe ratio and maximum drawdown
Show Solution
# Solution
data = vbt.YFData.download("^NSEBANK", start="2022-01-01", end="2024-01-01")
close = data.get('Close')
# Calculate Bollinger Bands
bb = vbt.BBANDS.run(close, window=20, stdev=2)
# Generate signals
entries = close <= bb.lower_band
exits = close >= bb.upper_band
# Backtest
portfolio = vbt.Portfolio.from_signals(
close, entries, exits,
init_cash=10_00_000,
fees=0.0003
)
print(f"Total Return: {portfolio.total_return():.2%}")
print(f"Sharpe Ratio: {portfolio.sharpe_ratio():.2f}")
print(f"Max Drawdown: {portfolio.max_drawdown():.2%}")
portfolio.plot().show()
Exercise 3: NIFTY 50 Sector Rotation
Create a sector rotation strategy:
- • Use IT, Banking, and Pharma sector leaders
- • Rotate based on 1-month momentum
- • Rebalance monthly
- • Compare with equal-weight portfolio
Try to implement this advanced strategy using the concepts learned!
Next Steps
Congratulations! 🎉
You've completed the Getting Started module. You now know how to:
- Install and configure VectorBT
- Download Indian stock market data
- Create and backtest trading strategies
- Analyze performance metrics
- Visualize results with interactive charts