Python library for backtesting and analyzing trading strategies at scale
—
Comprehensive backtesting engine for strategy evaluation with detailed performance metrics, trade analysis, and risk management. The portfolio module provides the core functionality for simulating trading strategies and analyzing their performance.
Create portfolios from trading signals or custom order functions with flexible configuration options for initial capital, fees, slippage, and execution logic.
class Portfolio:
"""
Main class for portfolio simulation and analysis.
Provides static methods for portfolio construction and instance methods
for performance analysis and visualization.
"""
@classmethod
def from_signals(cls, close, entries, exits, **kwargs):
"""
Create portfolio from entry and exit signals.
Parameters:
- close: pd.Series or pd.DataFrame, closing prices
- entries: pd.Series or pd.DataFrame, boolean entry signals
- exits: pd.Series or pd.DataFrame, boolean exit signals
- init_cash: float, initial capital (default: 100)
- size: float or array-like, position size (default: inf)
- fees: float, trading fees as percentage (default: 0)
- slippage: float, slippage as percentage (default: 0)
- freq: str, frequency for calculations (default: 'D')
Returns:
Portfolio: Configured portfolio instance
"""
@classmethod
def from_orders(cls, close, orders, **kwargs):
"""
Create portfolio from order records.
Parameters:
- close: pd.Series or pd.DataFrame, closing prices
- orders: structured array, order records with fields like size, price
- init_cash: float, initial capital
Returns:
Portfolio: Configured portfolio instance
"""
@classmethod
def from_order_func(cls, close, order_func, **kwargs):
"""
Create portfolio from custom order function.
Parameters:
- close: pd.Series or pd.DataFrame, closing prices
- order_func: callable, function generating orders
Returns:
Portfolio: Configured portfolio instance
"""
@classmethod
def from_holding(cls, close, **kwargs):
"""
Create buy-and-hold portfolio.
Parameters:
- close: pd.Series or pd.DataFrame, closing prices
- init_cash: float, initial capital
Returns:
Portfolio: Buy-and-hold portfolio instance
"""
@classmethod
def from_random_signals(cls, close, n, **kwargs):
"""
Create portfolio from random signals.
Parameters:
- close: pd.Series or pd.DataFrame, closing prices
- n: int or list, number of random signals to generate
- seed: int, random seed for reproducibility
Returns:
Portfolio: Portfolio with random signals
"""
@property
def orders(self):
"""Access to order records."""
@property
def trades(self):
"""Access to trade records."""
@property
def positions(self):
"""Access to position records."""
@property
def drawdowns(self):
"""Access to drawdown records."""
def value(self):
"""Portfolio value over time."""
def cash(self):
"""Cash balance over time."""
def asset_value(self):
"""Asset value over time."""Comprehensive suite of performance and risk metrics for strategy evaluation including returns, volatility, and risk-adjusted measures.
def total_return(self):
"""
Calculate total return of the portfolio.
Returns:
float or pd.Series: Total return as percentage
"""
def annualized_return(self, freq=None):
"""
Calculate annualized return.
Parameters:
- freq: str, frequency for annualization
Returns:
float or pd.Series: Annualized return percentage
"""
def volatility(self, freq=None):
"""
Calculate volatility (standard deviation of returns).
Returns:
float or pd.Series: Volatility as percentage
"""
def sharpe_ratio(self, risk_free_rate=0, freq=None):
"""
Calculate Sharpe ratio.
Parameters:
- risk_free_rate: float, risk-free rate (default: 0)
- freq: str, frequency for calculations
Returns:
float or pd.Series: Sharpe ratio
"""
def max_drawdown(self):
"""
Calculate maximum drawdown.
Returns:
float or pd.Series: Maximum drawdown as percentage
"""
def calmar_ratio(self):
"""
Calculate Calmar ratio (annualized return / max drawdown).
Returns:
float or pd.Series: Calmar ratio
"""
def sortino_ratio(self, risk_free_rate=0):
"""
Calculate Sortino ratio.
Parameters:
- risk_free_rate: float, risk-free rate
Returns:
float or pd.Series: Sortino ratio
"""Access detailed portfolio state including cash, shares, value, and position information throughout the simulation period.
def cash(self):
"""
Get cash balances over time.
Returns:
pd.Series or pd.DataFrame: Cash balances
"""
def shares(self):
"""
Get share holdings over time.
Returns:
pd.Series or pd.DataFrame: Share quantities
"""
def value(self):
"""
Get total portfolio value over time.
Returns:
pd.Series or pd.DataFrame: Portfolio values
"""
def returns(self):
"""
Get portfolio returns.
Returns:
pd.Series or pd.DataFrame: Period returns
"""
def cumulative_returns(self):
"""
Get cumulative returns.
Returns:
pd.Series or pd.DataFrame: Cumulative returns
"""Detailed analysis of individual trades including entry/exit points, holding periods, profit/loss, and trade statistics.
class Trades:
"""
Trade record analysis providing detailed trade statistics.
"""
def count(self):
"""Get number of trades."""
def pnl(self):
"""Get profit/loss for each trade."""
def returns(self):
"""Get returns for each trade."""
def duration(self):
"""Get duration of each trade."""
def win_rate(self):
"""Calculate win rate percentage."""
def profit_factor(self):
"""Calculate profit factor (gross profit / gross loss)."""
class EntryTrades:
"""Analysis of entry trades (long positions)."""
class ExitTrades:
"""Analysis of exit trades (short positions)."""Analysis of order execution including fill rates, rejected orders, and execution statistics.
class Orders:
"""
Order record analysis for examining execution details.
"""
def count(self):
"""Get number of orders."""
def size(self):
"""Get order sizes."""
def price(self):
"""Get order prices."""
def fees(self):
"""Get trading fees paid."""
def side(self):
"""Get order sides (buy/sell)."""
class Logs:
"""Execution log analysis for detailed order processing information."""Analysis of position holdings including position sizes, duration, and exposure metrics.
class Positions:
"""
Position analysis providing insights into holdings and exposure.
"""
def count(self):
"""Get number of positions."""
def size(self):
"""Get position sizes."""
def duration(self):
"""Get position durations."""
def pnl(self):
"""Get position profit/loss."""Detailed drawdown analysis including underwater curves, recovery periods, and drawdown statistics.
def drawdown(self):
"""
Calculate drawdown series.
Returns:
pd.Series or pd.DataFrame: Drawdown percentages
"""
def drawdowns(self):
"""
Get drawdown periods analysis.
Returns:
Drawdowns: Drawdown analysis object
"""class InitCashMode(IntEnum):
"""Initial cash calculation modes."""
Auto = 0
AutoAlign = 1
class CallSeqType(IntEnum):
"""Order call sequence types."""
Default = 0
Reversed = 1
Random = 2
Auto = 3
class SizeType(IntEnum):
"""Position sizing types."""
Amount = 0
Value = 1
Percent = 2
TargetAmount = 3
TargetValue = 4
TargetPercent = 5
class Direction(IntEnum):
"""Trade direction."""
LongOnly = 0
ShortOnly = 1
Both = 2
class OrderStatus(IntEnum):
"""Order execution status."""
Filled = 0
Ignored = 1
Rejected = 2
class OrderSide(IntEnum):
"""Order side."""
Buy = 0
Sell = 1
class TradeDirection(IntEnum):
"""Trade direction classification."""
Long = 0
Short = 1
class TradeStatus(IntEnum):
"""Trade status."""
Open = 0
Closed = 1import vectorbt as vbt
import pandas as pd
# Get data
data = vbt.YFData.download("AAPL", start="2020-01-01", end="2023-01-01")
close = data.get("Close")
# Simple moving average strategy
fast_ma = vbt.MA.run(close, 20)
slow_ma = vbt.MA.run(close, 50)
entries = fast_ma.ma_crossed_above(slow_ma.ma)
exits = fast_ma.ma_crossed_below(slow_ma.ma)
# Create portfolio
portfolio = vbt.Portfolio.from_signals(
close=close,
entries=entries,
exits=exits,
init_cash=10000,
fees=0.001 # 0.1% fees
)
# Analyze performance
print(f"Total Return: {portfolio.total_return():.2%}")
print(f"Sharpe Ratio: {portfolio.sharpe_ratio():.2f}")
print(f"Max Drawdown: {portfolio.max_drawdown():.2%}")
print(f"Number of Trades: {portfolio.trades.count()}")
print(f"Win Rate: {portfolio.trades.win_rate():.2%}")# Download multiple assets
symbols = ["AAPL", "GOOGL", "MSFT", "TSLA"]
data = vbt.YFData.download(symbols, start="2020-01-01", end="2023-01-01")
close = data.get("Close")
# Equal weight rebalancing strategy
rebalance_freq = "ME" # Monthly
target_weights = pd.Series([0.25, 0.25, 0.25, 0.25], index=symbols)
# Create custom order function for rebalancing
def rebalance_orders(close, target_weights):
# Implementation for rebalancing logic
pass
portfolio = vbt.Portfolio.from_order_func(
close=close,
order_func=rebalance_orders,
init_cash=100000
)Install with Tessl CLI
npx tessl i tessl/pypi-vectorbt