Try Live
Add Docs
Rankings
Pricing
Enterprise
Docs
Install
Theme
Install
Docs
Pricing
Enterprise
More...
More...
Try Live
Rankings
Create API Key
Add Docs
VectorBT
https://github.com/polakowo/vectorbt
Admin
vectorbt is a Python library for backtesting trading strategies with a focus on speed and ease of
...
Tokens:
161,616
Snippets:
1,407
Trust Score:
8.4
Update:
2 weeks ago
Context
Skills
Chat
Benchmark
89.1
Suggestions
Latest
Show doc for...
Code
Info
Show Results
Context Summary (auto-generated)
Raw
Copy
Link
# VectorBT VectorBT is a Python library for backtesting and analyzing trading strategies at scale. It leverages vectorized operations with pandas, NumPy, and Numba to enable testing thousands of trading ideas in seconds. The library provides a composable API for rapid experimentation, making it suitable for both human researchers and AI-driven workflows. The core functionality includes fast portfolio backtesting with trades, positions, drawdowns, and performance analysis. It features a rich indicator ecosystem with support for custom indicators and popular TA libraries (TA-Lib, Pandas TA), built-in data access from multiple sources (Yahoo Finance, CCXT, Binance, Alpaca), signal-based tooling, and interactive visualization with Plotly. The library excels at hyperparameter optimization through flexible broadcasting for multi-asset analysis and large parameter sweeps. ## Data Download - Yahoo Finance Download historical price data from Yahoo Finance using `YFData`. Supports stocks, ETFs, cryptocurrencies, and other Yahoo Finance symbols with flexible date ranges and intervals. ```python import vectorbt as vbt # Download single symbol with default settings (max period) data = vbt.YFData.download("BTC-USD") price = data.get("Close") print(price.tail()) # Download with specific date range and interval yf_data = vbt.YFData.download( "TSLA", start='2021-04-12 09:30:00 -0400', end='2021-04-12 15:30:00 -0400', interval='1m' ) ohlcv = yf_data.get() print(ohlcv) # Output: DataFrame with Open, High, Low, Close, Volume, Dividends, Stock Splits # Download multiple symbols symbols = ["BTC-USD", "ETH-USD", "XRP-USD"] data = vbt.YFData.download(symbols, missing_index="drop") prices = data.get("Close") print(prices.head()) # Update existing data with new bars updated_data = yf_data.update(end='2021-04-12 16:00:00 -0400') ``` ## Data Download - Binance Download cryptocurrency OHLCV data from Binance exchange using `BinanceData`. Requires python-binance package and supports all Binance trading pairs and timeframes. ```python import vectorbt as vbt # Download recent 2 hours of 1-minute data binance_data = vbt.BinanceData.download( "BTCUSDT", start='2 hours ago UTC', end='now UTC', interval='1m' ) df = binance_data.get() print(df.columns) # Output: Open, High, Low, Close, Volume, Close time, Quote volume, # Number of trades, Taker base volume, Taker quote volume # Download with custom client credentials from binance.client import Client client = Client(api_key="your_key", api_secret="your_secret") data = vbt.BinanceData.download("ETHUSDT", client=client, interval='1h') # Update data incrementally import time time.sleep(60) binance_data = binance_data.update() ``` ## Data Download - CCXT Download data from 100+ cryptocurrency exchanges using the unified CCXT interface with `CCXTData`. Supports any exchange that provides OHLCV data. ```python import vectorbt as vbt # Download from Binance (default) using CCXT ccxt_data = vbt.CCXTData.download( "BTC/USDT", start='2 hours ago UTC', end='now UTC', timeframe='1m' ) print(ccxt_data.get()) # Download from different exchanges kraken_data = vbt.CCXTData.download( "BTC/USD", exchange='kraken', timeframe='1h', start='1 week ago UTC' ) # With exchange configuration config = {'enableRateLimit': True, 'timeout': 30000} data = vbt.CCXTData.download( "ETH/USDT", exchange='binance', config=config, timeframe='15m' ) ``` ## Data Download - Alpaca Download stock and crypto data from Alpaca Markets using `AlpacaData`. Requires alpaca-py package and Alpaca API credentials. ```python import vectorbt as vbt # Configure Alpaca credentials in settings or environment # vbt.settings.data['alpaca']['api_key'] = 'your_key' # vbt.settings.data['alpaca']['secret_key'] = 'your_secret' # Download stock data alpaca_data = vbt.AlpacaData.download( "AAPL", start='2 hours ago UTC', end='15 minutes ago UTC', timeframe='1m' ) print(alpaca_data.get()) # Download crypto data (use "/" in symbol) crypto_data = vbt.AlpacaData.download( "BTC/USD", timeframe='1h', start='1 day ago UTC' ) # Multiple timeframes daily_data = vbt.AlpacaData.download("MSFT", timeframe='1d', start='1 year ago') ``` ## Synthetic Data - GBM Generate synthetic price data using Geometric Brownian Motion with `GBMData`. Useful for strategy testing and Monte Carlo simulations. ```python import vectorbt as vbt # Generate single synthetic price series gbm_data = vbt.GBMData.download( 'GBM', start='2 hours ago', end='now', freq='1min', seed=42 # For reproducibility ) print(gbm_data.get().head()) # Generate with custom parameters gbm_data = vbt.GBMData.download( 'SYNTHETIC', start='2020-01-01', end='2021-01-01', freq='1D', S0=100.0, # Initial price mu=0.05, # Drift (mean return) sigma=0.2, # Volatility I=5, # Number of paths (columns) seed=42 ) paths = gbm_data.get() print(paths.head()) # Update with new data points gbm_data = gbm_data.update() ``` ## Portfolio - Buy and Hold Create a buy-and-hold portfolio using `Portfolio.from_holding`. The simplest portfolio simulation that invests initial cash at the start and holds until the end. ```python import vectorbt as vbt # Download data data = vbt.YFData.download("BTC-USD", start="2020-01-01") price = data.get("Close") # Create buy-and-hold portfolio pf = vbt.Portfolio.from_holding(price, init_cash=10000) # Get key metrics print(f"Total Profit: ${pf.total_profit():.2f}") print(f"Total Return: {pf.total_return() * 100:.2f}%") print(f"Max Drawdown: {pf.max_drawdown() * 100:.2f}%") print(f"Sharpe Ratio: {pf.sharpe_ratio():.3f}") # Full statistics print(pf.stats()) # Plot portfolio performance fig = pf.plot() fig.show() ``` ## Portfolio - From Signals Create a portfolio from entry/exit signals using `Portfolio.from_signals`. Supports long-only, short-only, and both directions with stop-loss and take-profit orders. ```python import vectorbt as vbt # Download data and calculate indicators data = vbt.YFData.download("BTC-USD", start="2020-01-01") price = data.get("Close") # Calculate moving averages fast_ma = vbt.MA.run(price, 10) slow_ma = vbt.MA.run(price, 50) # Generate crossover signals entries = fast_ma.ma_crossed_above(slow_ma) exits = fast_ma.ma_crossed_below(slow_ma) # Create portfolio with default settings (invest all cash) pf = vbt.Portfolio.from_signals( price, entries, exits, init_cash=10000, fees=0.001, # 0.1% fees slippage=0.001 # 0.1% slippage ) print(f"Total Return: {pf.total_return() * 100:.2f}%") print(f"Number of Trades: {pf.trades.count()}") # With fixed position size pf = vbt.Portfolio.from_signals( price, entries, exits, size=0.5, # 50% of cash per trade init_cash=10000 ) # With stop-loss and take-profit pf = vbt.Portfolio.from_signals( price, entries, exits, init_cash=10000, sl_stop=0.05, # 5% stop-loss tp_stop=0.10 # 10% take-profit ) # Short-only strategy pf_short = vbt.Portfolio.from_signals( price, entries, exits, direction='shortonly', init_cash=10000 ) ``` ## Portfolio - From Orders Create a portfolio from explicit order sizes using `Portfolio.from_orders`. Most direct simulation method where you specify exact order sizes for each timestamp. ```python import vectorbt as vbt import pandas as pd import numpy as np # Create price data price = pd.DataFrame({ 'a': [1, 2, 3, 4, 5], 'b': [5, 4, 3, 2, 1] }) # Define order sizes (positive = buy, negative = sell) size = pd.Series([1, -1, 1, -1, 0]) # Create portfolio with different directions per column pf = vbt.Portfolio.from_orders( price, size, direction=['longonly', 'shortonly'], fees=0.01, init_cash=100 ) # View order records print(pf.orders.records_readable) # Using value-based sizing (order value in $) result = pd.DataFrame(np.random.randn(100, 3) * 10) # Signal values size = result / price # Convert to share counts pf = vbt.Portfolio.from_orders(price, size, init_cash='autoalign') # Accumulating orders (multiple positions) pf = vbt.Portfolio.from_orders( price, size=1, # Buy 1 share each bar accumulate=True, init_cash=1000 ) ``` ## Portfolio - From Order Function Create a portfolio with custom logic using `Portfolio.from_order_func`. Most flexible method using Numba-compiled callbacks for complex strategies. ```python import vectorbt as vbt import numpy as np from numba import njit from vectorbt.portfolio import nb from vectorbt.portfolio.enums import Direction # Define order function @njit def order_func_nb(c, size, direction, fees): return nb.order_nb( price=c.close[c.i, c.col], size=size[c.i], direction=direction[c.col], fees=fees ) # Setup data price = pd.DataFrame({'a': [1, 2, 3, 4], 'b': [4, 3, 2, 1]}) size = np.array([1, -1, 1, -1]) direction = np.array([Direction.LongOnly, Direction.ShortOnly]) # Run simulation pf = vbt.Portfolio.from_order_func( price, order_func_nb, size, direction, 0.01 # Arguments passed to order_func_nb ) print(pf.orders.records_readable) # With segment preparation (process groups of columns together) @njit def segment_prep_func_nb(c): # Called once per row before processing columns return () @njit def order_func_with_prep_nb(c, size): if c.i == 0: return nb.order_nb(price=c.close[c.i, c.col], size=size) return nb.order_nb() # No order pf = vbt.Portfolio.from_order_func( price, order_func_with_prep_nb, 10.0, # Buy 10 shares at start segment_prep_func_nb=segment_prep_func_nb ) ``` ## Portfolio - Random Signals Generate portfolios with random entry/exit signals using `Portfolio.from_random_signals`. Useful for benchmarking strategies against random trading. ```python import vectorbt as vbt import numpy as np # Download data symbols = ["BTC-USD", "ETH-USD"] data = vbt.YFData.download(symbols, missing_index="drop") price = data.get("Close") # Generate 1000 random strategies with varying trade counts n = np.random.randint(10, 101, size=1000).tolist() pf = vbt.Portfolio.from_random_signals( price, n=n, # Number of entries per strategy init_cash=100, seed=42 # For reproducibility ) # Analyze results mean_expectancy = pf.trades.expectancy().groupby(["randnx_n", "symbol"]).mean() print(mean_expectancy.describe()) # Compare to systematic strategy fast_ma = vbt.MA.run(price, 10) slow_ma = vbt.MA.run(price, 50) entries = fast_ma.ma_crossed_above(slow_ma) exits = fast_ma.ma_crossed_below(slow_ma) systematic_pf = vbt.Portfolio.from_signals(price, entries, exits, init_cash=100) print(f"Random Mean Return: {pf.total_return().mean():.2%}") print(f"Systematic Return: {systematic_pf.total_return().mean():.2%}") ``` ## Portfolio - Statistics and Analysis Access comprehensive portfolio statistics and performance metrics. VectorBT provides dozens of built-in metrics including risk-adjusted returns, drawdowns, and trade analysis. ```python import vectorbt as vbt # Create portfolio data = vbt.YFData.download("BTC-USD", start="2020-01-01") price = data.get("Close") pf = vbt.Portfolio.from_holding(price, init_cash=10000) # Full statistics stats = pf.stats() print(stats) # Includes: Start/End Value, Total Return, Benchmark Return, # Max Drawdown, Sharpe/Calmar/Sortino Ratios, Win Rate, etc. # Individual metrics print(f"Total Return: {pf.total_return():.2%}") print(f"Annual Return: {pf.annualized_return():.2%}") print(f"Max Drawdown: {pf.max_drawdown():.2%}") print(f"Sharpe Ratio: {pf.sharpe_ratio():.3f}") print(f"Sortino Ratio: {pf.sortino_ratio():.3f}") print(f"Calmar Ratio: {pf.calmar_ratio():.3f}") # Trade analysis print(f"Total Trades: {pf.trades.count()}") print(f"Win Rate: {pf.trades.win_rate():.2%}") print(f"Profit Factor: {pf.trades.profit_factor():.2f}") print(f"Expectancy: ${pf.trades.expectancy():.2f}") # Drawdown analysis print(f"Max Drawdown Duration: {pf.drawdowns.max_duration()}") print(f"Average Drawdown: {pf.drawdowns.avg_drawdown():.2%}") # Value over time portfolio_value = pf.value() daily_returns = pf.returns() cumulative_returns = pf.cumulative_returns() ``` ## Portfolio - Multi-Asset and Grouping Analyze portfolios across multiple assets with optional cash sharing between groups. Supports column grouping for combined portfolio analysis. ```python import vectorbt as vbt import pandas as pd import numpy as np # Download multi-asset data symbols = ['BTC-USD', 'ETH-USD', 'XRP-USD', 'BNB-USD', 'LTC-USD', 'BCH-USD'] data = vbt.YFData.download(symbols, start='2020-01-01', end='2021-01-01') ohlcv = data.concat() price = ohlcv['Close'] # Generate signals size = pd.DataFrame(np.random.randn(len(price), len(symbols)) * 100, index=price.index, columns=price.columns) size = size / ohlcv['Open'] # Independent portfolios per asset pf = vbt.Portfolio.from_orders( ohlcv['Close'], size, price=ohlcv['Open'], init_cash='autoalign', # Auto-calculate required cash fees=0.001 ) print(pf.total_profit()) # Per symbol # Grouped portfolios with cash sharing group_by = pd.Index(['crypto1', 'crypto1', 'crypto1', 'crypto2', 'crypto2', 'crypto2']) comb_pf = vbt.Portfolio.from_orders( ohlcv['Close'], size, price=ohlcv['Open'], init_cash='autoalign', fees=0.001, group_by=group_by, cash_sharing=True # Share cash within groups ) # Group-level metrics print(comb_pf.total_profit()) # Per group # Column-level metrics within grouped portfolio print(comb_pf.total_profit(group_by=False)) # Per symbol # Indexing grouped portfolio crypto1_pf = comb_pf['crypto1'] print(crypto1_pf.stats()) ``` ## Indicators - Moving Average Calculate moving averages using the built-in `MA` indicator. Supports both simple (SMA) and exponential (EMA) moving averages with multiple window sizes. ```python import vectorbt as vbt # Download data data = vbt.YFData.download("BTC-USD", start="2020-01-01") price = data.get("Close") # Simple moving average ma = vbt.MA.run(price, window=20) print(ma.ma.tail()) # Multiple windows at once ma_multi = vbt.MA.run(price, window=[10, 20, 50]) print(ma_multi.ma.tail()) # Output has MultiIndex columns: (ma_window, ma_ewm) # Exponential moving average ema = vbt.MA.run(price, window=20, ewm=True) print(ema.ma.tail()) # Crossover signals fast_ma = vbt.MA.run(price, 10) slow_ma = vbt.MA.run(price, 50) # Built-in crossover detection crossed_above = fast_ma.ma_crossed_above(slow_ma) crossed_below = fast_ma.ma_crossed_below(slow_ma) print(f"Bullish crossovers: {crossed_above.sum()}") print(f"Bearish crossovers: {crossed_below.sum()}") # Plot fig = ma.plot() fig.show() ``` ## Indicators - Bollinger Bands Calculate Bollinger Bands using the `BBANDS` indicator. Includes upper band, lower band, middle band, %B, and bandwidth. ```python import vectorbt as vbt # Download data data = vbt.YFData.download("BTC-USD", start="2020-01-01") price = data.get("Close") # Calculate Bollinger Bands (default: 20-period, 2 std) bbands = vbt.BBANDS.run(price) # Access band values print("Middle Band:", bbands.middle.tail()) print("Upper Band:", bbands.upper.tail()) print("Lower Band:", bbands.lower.tail()) # Custom parameters bbands_custom = vbt.BBANDS.run( price, window=20, alpha=2.5, # Standard deviations ewm=True # Use EMA instead of SMA ) # %B indicator (position within bands) percent_b = bbands.percent_b print("Percent B:", percent_b.tail()) # 0 = at lower band, 0.5 = at middle, 1 = at upper band # Bandwidth (volatility indicator) bandwidth = bbands.bandwidth print("Bandwidth:", bandwidth.tail()) # Generate signals oversold = percent_b < 0 # Price below lower band overbought = percent_b > 1 # Price above upper band # Plot fig = bbands.plot() fig.show() ``` ## Indicators - RSI Calculate the Relative Strength Index using the `RSI` indicator. Measures momentum to identify overbought and oversold conditions. ```python import vectorbt as vbt # Download data data = vbt.YFData.download("BTC-USD", start="2020-01-01") price = data.get("Close") # Calculate RSI (default: 14-period) rsi = vbt.RSI.run(price) print(rsi.rsi.tail()) # Multiple periods rsi_multi = vbt.RSI.run(price, window=[7, 14, 21]) print(rsi_multi.rsi.tail()) # EMA-based RSI (Wilder's smoothing) rsi_ema = vbt.RSI.run(price, window=14, ewm=True) # Generate signals oversold = rsi.rsi < 30 overbought = rsi.rsi > 70 # Crossover signals crossed_above_30 = rsi.rsi_crossed_above(30) crossed_below_70 = rsi.rsi_crossed_below(70) # RSI divergence detection (price makes new high, RSI doesn't) price_highs = price.rolling(20).max() == price rsi_highs = rsi.rsi.rolling(20).max() == rsi.rsi bearish_divergence = price_highs & ~rsi_highs # Plot with overbought/oversold levels fig = rsi.plot(levels=(30, 70)) fig.show() ``` ## Indicators - MACD Calculate the Moving Average Convergence Divergence using the `MACD` indicator. Includes MACD line, signal line, and histogram. ```python import vectorbt as vbt # Download data data = vbt.YFData.download("BTC-USD", start="2020-01-01") price = data.get("Close") # Calculate MACD (default: 12/26/9) macd = vbt.MACD.run(price) # Access components print("MACD Line:", macd.macd.tail()) print("Signal Line:", macd.signal.tail()) print("Histogram:", macd.hist.tail()) # Custom parameters macd_custom = vbt.MACD.run( price, fast_window=8, slow_window=21, signal_window=5 ) # Generate signals bullish_cross = macd.macd_crossed_above(macd.signal) bearish_cross = macd.macd_crossed_below(macd.signal) # Zero line crossovers above_zero = macd.macd_crossed_above(0) below_zero = macd.macd_crossed_below(0) # Histogram turning points hist_turning_up = (macd.hist > macd.hist.shift(1)) & (macd.hist.shift(1) < macd.hist.shift(2)) hist_turning_down = (macd.hist < macd.hist.shift(1)) & (macd.hist.shift(1) > macd.hist.shift(2)) # Plot fig = macd.plot() fig.show() ``` ## Indicators - ATR and Stochastic Calculate Average True Range (volatility) and Stochastic Oscillator (momentum) indicators. ```python import vectorbt as vbt # Download OHLCV data data = vbt.YFData.download("BTC-USD", start="2020-01-01") high = data.get("High") low = data.get("Low") close = data.get("Close") # ATR - Average True Range atr = vbt.ATR.run(high, low, close, window=14) print("ATR:", atr.atr.tail()) # ATR for position sizing (volatility-adjusted) atr_pct = atr.atr / close * 100 position_size = 1 / atr_pct # Inverse volatility sizing # Stochastic Oscillator stoch = vbt.STOCH.run(high, low, close, k_window=14, d_window=3) print("Stochastic %K:", stoch.percent_k.tail()) print("Stochastic %D:", stoch.percent_d.tail()) # Stochastic signals oversold = stoch.percent_k < 20 overbought = stoch.percent_k > 80 bullish_cross = stoch.percent_k_crossed_above(stoch.percent_d) bearish_cross = stoch.percent_k_crossed_below(stoch.percent_d) # Combined signal: oversold + bullish cross buy_signal = oversold.shift(1) & bullish_cross # Plot fig = stoch.plot() fig.show() ``` ## Indicators - Custom with IndicatorFactory Create custom indicators using `IndicatorFactory`. Build any indicator with automatic parameter optimization and signal generation. ```python import vectorbt as vbt import numpy as np from numba import njit # Simple custom indicator @njit def custom_ma_nb(close, window): """Custom moving average with Numba acceleration.""" out = np.full(close.shape, np.nan) for col in range(close.shape[1]): for i in range(window, close.shape[0]): out[i, col] = np.mean(close[i-window:i, col]) return out # Create indicator class CustomMA = vbt.IndicatorFactory( input_names=['close'], param_names=['window'], output_names=['ma'] ).from_apply_func(custom_ma_nb) # Use the indicator price = vbt.YFData.download("BTC-USD").get("Close") custom_ma = CustomMA.run(price, window=[10, 20, 50]) print(custom_ma.ma.tail()) # More complex indicator with multiple outputs @njit def bb_custom_nb(close, window, mult): """Custom Bollinger Bands.""" ma = np.full(close.shape, np.nan) upper = np.full(close.shape, np.nan) lower = np.full(close.shape, np.nan) for col in range(close.shape[1]): for i in range(window, close.shape[0]): data = close[i-window:i, col] ma[i, col] = np.mean(data) std = np.std(data) upper[i, col] = ma[i, col] + mult * std lower[i, col] = ma[i, col] - mult * std return ma, upper, lower CustomBB = vbt.IndicatorFactory( input_names=['close'], param_names=['window', 'mult'], output_names=['ma', 'upper', 'lower'] ).from_apply_func(bb_custom_nb) bb = CustomBB.run(price, window=20, mult=[1.5, 2.0, 2.5]) print(bb.upper.tail()) # Parameter combinations with run_combs fast, slow = CustomMA.run_combs(price, window=[10, 20, 30, 50]) crossovers = fast.ma_crossed_above(slow.ma) print(f"Total crossover signals: {crossovers.sum().sum()}") ``` ## Indicators - TA-Lib Integration Use TA-Lib indicators through VectorBT's `IndicatorFactory.from_talib`. Provides vectorized versions of all TA-Lib functions with automatic parameter optimization. ```python import vectorbt as vbt # Download OHLCV data data = vbt.YFData.download("BTC-USD", start="2020-01-01") open_price = data.get("Open") high = data.get("High") low = data.get("Low") close = data.get("Close") # Create TA-Lib indicator class SMA = vbt.IndicatorFactory.from_talib('SMA') sma = SMA.run(close, timeperiod=[10, 20, 50]) print(sma.real.tail()) # RSI from TA-Lib RSI = vbt.IndicatorFactory.from_talib('RSI') rsi = RSI.run(close, timeperiod=14) print(rsi.real.tail()) # BBANDS from TA-Lib BBANDS = vbt.IndicatorFactory.from_talib('BBANDS') bbands = BBANDS.run(close, timeperiod=20, nbdevup=2, nbdevdn=2) print("Upper:", bbands.upperband.tail()) print("Middle:", bbands.middleband.tail()) print("Lower:", bbands.lowerband.tail()) # Pattern recognition CDL_DOJI = vbt.IndicatorFactory.from_talib('CDLDOJI') doji = CDL_DOJI.run(open_price, high, low, close) doji_signals = doji.integer != 0 # Run all pattern recognition import talib patterns = [] for pattern in talib.get_function_groups()['Pattern Recognition']: PatternInd = vbt.IndicatorFactory.from_talib(pattern) result = PatternInd.run(open_price, high, low, close) patterns.append(result.integer) # Shortcut function rsi = vbt.talib('RSI').run(close, timeperiod=14) ``` ## Hyperparameter Optimization Test thousands of parameter combinations efficiently using VectorBT's broadcasting and `run_combs`. Visualize results with heatmaps. ```python import vectorbt as vbt import numpy as np # Download data symbols = ["BTC-USD", "ETH-USD", "XRP-USD"] data = vbt.YFData.download(symbols, start="2020-01-01", missing_index="drop") price = data.get("Close") # Test all combinations of fast/slow MA windows windows = np.arange(5, 51) fast_ma, slow_ma = vbt.MA.run_combs( price, window=windows, r=2, # Combinations of 2 short_names=['fast', 'slow'] ) # Generate signals and backtest entries = fast_ma.ma_crossed_above(slow_ma) exits = fast_ma.ma_crossed_below(slow_ma) pf = vbt.Portfolio.from_signals( price, entries, exits, size=np.inf, fees=0.001, freq="1D" ) # Analyze results total_returns = pf.total_return() print(f"Total combinations tested: {len(total_returns)}") print(f"Best return: {total_returns.max():.2%}") print(f"Worst return: {total_returns.min():.2%}") # Find best parameters best_idx = total_returns.idxmax() print(f"Best parameters: {best_idx}") # Create heatmap visualization fig = pf.total_return().vbt.heatmap( x_level='fast_window', y_level='slow_window', slider_level='symbol', symmetric=True, trace_kwargs=dict( colorbar=dict(title="Total Return", tickformat="%") ) ) fig.show() # Get stats for specific configuration best_pf = pf[best_idx] print(best_pf.stats()) ``` ## Visualization - Portfolio Plots Create interactive visualizations of portfolio performance, trades, and metrics using Plotly integration. ```python import vectorbt as vbt # Create portfolio data = vbt.YFData.download("BTC-USD", start="2020-01-01") price = data.get("Close") fast_ma = vbt.MA.run(price, 10) slow_ma = vbt.MA.run(price, 50) entries = fast_ma.ma_crossed_above(slow_ma) exits = fast_ma.ma_crossed_below(slow_ma) pf = vbt.Portfolio.from_signals(price, entries, exits, init_cash=10000, fees=0.001) # Full portfolio plot (value, drawdowns, trades) fig = pf.plot() fig.show() # Individual component plots fig_value = pf.value().vbt.plot(title="Portfolio Value") fig_value.show() fig_returns = pf.cumulative_returns().vbt.plot(title="Cumulative Returns") fig_returns.show() fig_drawdowns = pf.drawdowns.plot() fig_drawdowns.show() # Trade visualization fig_trades = pf.trades.plot() fig_trades.show() # Orders visualization fig_orders = pf.orders.plot() fig_orders.show() # Subplots with custom layout fig = vbt.make_subplots(rows=2, cols=1, shared_xaxes=True) pf.value().vbt.plot(add_trace_kwargs=dict(row=1, col=1), fig=fig) pf.drawdowns.drawdown.vbt.plot(add_trace_kwargs=dict(row=2, col=1), fig=fig) fig.update_layout(height=600) fig.show() ``` ## Visualization - Heatmaps and Analysis Create heatmaps, scatter plots, and other analytical visualizations for multi-dimensional data exploration. ```python import vectorbt as vbt import numpy as np # Multi-parameter optimization results data = vbt.YFData.download("BTC-USD", start="2020-01-01") price = data.get("Close") windows = np.arange(5, 31, 5) fast_ma, slow_ma = vbt.MA.run_combs(price, window=windows, r=2, short_names=['fast', 'slow']) entries = fast_ma.ma_crossed_above(slow_ma) exits = fast_ma.ma_crossed_below(slow_ma) pf = vbt.Portfolio.from_signals(price, entries, exits, fees=0.001) # Heatmap of returns by parameters returns = pf.total_return() fig = returns.vbt.heatmap( x_level='fast_window', y_level='slow_window', trace_kwargs=dict(colorscale='RdYlGn', zmid=0) ) fig.show() # Scatter plot sharpe = pf.sharpe_ratio() fig = vbt.make_figure() fig.add_scatter( x=returns.values, y=sharpe.values, mode='markers', text=[str(i) for i in returns.index], hovertemplate='Return: %{x:.2%}<br>Sharpe: %{y:.2f}<br>Params: %{text}' ) fig.update_layout(xaxis_title='Total Return', yaxis_title='Sharpe Ratio') fig.show() # Time series heatmap (for multiple assets/parameters over time) multi_data = vbt.YFData.download(["BTC-USD", "ETH-USD", "XRP-USD"], start="2020-01-01") multi_price = multi_data.get("Close") returns = multi_price.pct_change() fig = returns.vbt.ts_heatmap( trace_kwargs=dict(colorscale='RdYlGn', zmid=0) ) fig.show() # Box plot for distribution analysis trades = pf.trades.pnl fig = trades.vbt.boxplot() fig.show() ``` ## Walk-Forward Optimization Implement walk-forward optimization using VectorBT's splitters for robust strategy validation. ```python import vectorbt as vbt import numpy as np import pandas as pd # Download data data = vbt.YFData.download("BTC-USD", start="2018-01-01", end="2023-01-01") price = data.get("Close") # Create rolling window splitter splitter = vbt.RollingSplitter( price.index, n=252 * 2, # 2-year windows split=0.7, # 70% train, 30% test set_labels=['train', 'test'] ) # Visualize splits fig = splitter.plot() fig.show() # Walk-forward optimization windows = np.arange(10, 51, 5) results = [] for i, (train_idx, test_idx) in enumerate(splitter.split(price.index)): train_price = price.iloc[train_idx] test_price = price.iloc[test_idx] # Optimize on training set fast_ma, slow_ma = vbt.MA.run_combs(train_price, window=windows, r=2, short_names=['fast', 'slow']) entries = fast_ma.ma_crossed_above(slow_ma) exits = fast_ma.ma_crossed_below(slow_ma) train_pf = vbt.Portfolio.from_signals(train_price, entries, exits, fees=0.001) # Find best parameters best_params = train_pf.sharpe_ratio().idxmax() best_fast, best_slow = best_params[0], best_params[1] # Test on out-of-sample data fast_ma = vbt.MA.run(test_price, best_fast) slow_ma = vbt.MA.run(test_price, best_slow) entries = fast_ma.ma_crossed_above(slow_ma) exits = fast_ma.ma_crossed_below(slow_ma) test_pf = vbt.Portfolio.from_signals(test_price, entries, exits, fees=0.001) results.append({ 'fold': i, 'best_fast': best_fast, 'best_slow': best_slow, 'train_sharpe': train_pf[best_params].sharpe_ratio(), 'test_sharpe': test_pf.sharpe_ratio(), 'test_return': test_pf.total_return() }) results_df = pd.DataFrame(results) print(results_df) print(f"\nAverage OOS Sharpe: {results_df['test_sharpe'].mean():.3f}") print(f"Average OOS Return: {results_df['test_return'].mean():.2%}") ``` ## Pandas Accessors Use VectorBT's pandas accessors (`.vbt`) for enhanced DataFrame/Series operations including plotting, resampling, and transformations. ```python import vectorbt as vbt import pandas as pd import numpy as np # Download data data = vbt.YFData.download("BTC-USD", start="2020-01-01") price = data.get("Close") returns = price.pct_change() # Plotting accessor fig = price.vbt.plot(title="BTC Price") fig.show() fig = returns.vbt.histplot(title="Return Distribution") fig.show() # Resampling with aggregation weekly_price = price.vbt.resample('W').last() monthly_returns = returns.vbt.resample('M').sum() # Rolling operations rolling_mean = price.vbt.rolling_mean(20) rolling_std = price.vbt.rolling_std(20) # Drawdown analysis drawdown = price.vbt.to_drawdown_series() print(f"Current Drawdown: {drawdown.iloc[-1]:.2%}") # Signals accessor signals = pd.Series([True, False, True, True, False, True], index=pd.date_range('2020', periods=6)) first_signals = signals.vbt.signals.first() # First True in each sequence print(first_signals) # Ranking and normalization normalized = price.vbt.normalize() # 0-1 scaling zscore = (price - price.rolling(20).mean()) / price.rolling(20).std() # Concatenation with proper labeling prices = vbt.YFData.download(["BTC-USD", "ETH-USD"]).get("Close") combined = pd.DataFrame.vbt.concat( prices['BTC-USD'], prices['ETH-USD'], keys=['Bitcoin', 'Ethereum'] ) print(combined.tail()) # Empty DataFrame with structure empty = pd.DataFrame.vbt.empty_like(prices, fill_value=0.0) ``` ## Summary VectorBT provides a comprehensive toolkit for quantitative trading research with three primary use cases: rapid strategy backtesting through vectorized portfolio simulation (`Portfolio.from_signals`, `Portfolio.from_orders`), large-scale parameter optimization leveraging broadcasting and `run_combs` for testing thousands of configurations simultaneously, and multi-asset portfolio analysis with grouping and cash-sharing capabilities. The library integrates seamlessly with the pandas ecosystem through custom accessors while achieving high performance via Numba-accelerated computations. Integration patterns typically follow a data-indicator-portfolio-analysis workflow: fetch market data using built-in downloaders (`YFData`, `BinanceData`, `CCXTData`), compute technical indicators with the indicator factory system, simulate portfolios with the appropriate method based on strategy complexity, and analyze results using the extensive metrics and visualization tools. For production systems, VectorBT supports incremental data updates, scheduled automation via the `DataUpdater` class, and Telegram notifications for alerts. The `IndicatorFactory` pattern enables creation of reusable, optimized indicator classes that can be shared across projects and integrated with existing TA libraries through `from_talib` and `from_pandas_ta` adapters.