Vectorbt Backtest
Leverage the vectorbt library for high-performance vectorized backtesting with built-in hyperparameter optimization, detailed signal analysis, interactive performance visualization, and comprehensive strategy tear-sheet generation.
Backtesting Libraries – vectorbt
This notebook demonstrates the capabilities of vectorbt, a powerful Python library for high-performance backtesting of quantitative trading strategies. It focuses on vectorized computation, enabling efficient parameter optimization and strategy screening.
1. Dependency Installation
This section outlines the necessary Python package installations required to run the examples provided in this notebook. These packages include pandas for data manipulation, numpy for numerical operations, vectorbt for backtesting functionalities, and plotly for interactive visualizations.
# Install necessary libraries: pandas, numpy, vectorbt, and plotly.
# `vectorbt` is the primary backtesting library.
# `pandas` and `numpy` are fundamental for data handling.
# `plotly` is used for interactive visualizations of backtest results.
!pip install pandas numpy vectorbt plotlyRequirement already satisfied: pandas in /usr/local/lib/python3.12/dist-packages (2.2.2) Requirement already satisfied: numpy in /usr/local/lib/python3.12/dist-packages (2.0.2) Requirement already satisfied: vectorbt in /usr/local/lib/python3.12/dist-packages (1.0.0) Requirement already satisfied: plotly in /usr/local/lib/python3.12/dist-packages (5.24.1) Requirement already satisfied: python-dateutil>=2.8.2 in /usr/local/lib/python3.12/dist-packages (from pandas) (2.9.0.post0) Requirement already satisfied: pytz>=2020.1 in /usr/local/lib/python3.12/dist-packages (from pandas) (2025.2) Requirement already satisfied: tzdata>=2022.7 in /usr/local/lib/python3.12/dist-packages (from pandas) (2026.2) Requirement already satisfied: scipy in /usr/local/lib/python3.12/dist-packages (from vectorbt) (1.16.3) Requirement already satisfied: matplotlib in /usr/local/lib/python3.12/dist-packages (from vectorbt) (3.10.0) Requirement already satisfied: ipywidgets>=7.0.0 in /usr/local/lib/python3.12/dist-packages (from vectorbt) (7.7.1) Requirement already satisfied: anywidget in /usr/local/lib/python3.12/dist-packages (from vectorbt) (0.9.21) Requirement already satisfied: numba>=0.60 in /usr/local/lib/python3.12/dist-packages (from vectorbt) (0.60.0) Requirement already satisfied: dill in /usr/local/lib/python3.12/dist-packages (from vectorbt) (0.3.8) Requirement already satisfied: tqdm in /usr/local/lib/python3.12/dist-packages (from vectorbt) (4.67.3) Requirement already satisfied: dateparser in /usr/local/lib/python3.12/dist-packages (from vectorbt) (1.4.1) Requirement already satisfied: imageio in /usr/local/lib/python3.12/dist-packages (from vectorbt) (2.37.3) Requirement already satisfied: scikit-learn in /usr/local/lib/python3.12/dist-packages (from vectorbt) (1.6.1) Requirement already satisfied: schedule in /usr/local/lib/python3.12/dist-packages (from vectorbt) (1.2.2) Requirement already satisfied: requests in /usr/local/lib/python3.12/dist-packages (from vectorbt) (2.32.4) Requirement already satisfied: mypy_extensions in /usr/local/lib/python3.12/dist-packages (from vectorbt) (1.1.0) Requirement already satisfied: tenacity>=6.2.0 in /usr/local/lib/python3.12/dist-packages (from plotly) (9.1.4) Requirement already satisfied: packaging in /usr/local/lib/python3.12/dist-packages (from plotly) (26.2) Requirement already satisfied: ipykernel>=4.5.1 in /usr/local/lib/python3.12/dist-packages (from ipywidgets>=7.0.0->vectorbt) (6.17.1) Requirement already satisfied: ipython-genutils~=0.2.0 in /usr/local/lib/python3.12/dist-packages (from ipywidgets>=7.0.0->vectorbt) (0.2.0) Requirement already satisfied: traitlets>=4.3.1 in /usr/local/lib/python3.12/dist-packages (from ipywidgets>=7.0.0->vectorbt) (5.7.1) Requirement already satisfied: widgetsnbextension~=3.6.0 in /usr/local/lib/python3.12/dist-packages (from ipywidgets>=7.0.0->vectorbt) (3.6.10) Requirement already satisfied: ipython>=4.0.0 in /usr/local/lib/python3.12/dist-packages (from ipywidgets>=7.0.0->vectorbt) (7.34.0) Requirement already satisfied: jupyterlab-widgets>=1.0.0 in /usr/local/lib/python3.12/dist-packages (from ipywidgets>=7.0.0->vectorbt) (3.0.16) Requirement already satisfied: llvmlite<0.44,>=0.43.0dev0 in /usr/local/lib/python3.12/dist-packages (from numba>=0.60->vectorbt) (0.43.0) Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.12/dist-packages (from python-dateutil>=2.8.2->pandas) (1.17.0) Requirement already satisfied: psygnal>=0.8.1 in /usr/local/lib/python3.12/dist-packages (from anywidget->vectorbt) (0.15.1) Requirement already satisfied: typing-extensions>=4.2.0 in /usr/local/lib/python3.12/dist-packages (from anywidget->vectorbt) (4.15.0) Requirement already satisfied: regex>=2024.9.11 in /usr/local/lib/python3.12/dist-packages (from dateparser->vectorbt) (2025.11.3) Requirement already satisfied: tzlocal>=0.2 in /usr/local/lib/python3.12/dist-packages (from dateparser->vectorbt) (5.3.1) Requirement already satisfied: pillow>=8.3.2 in /usr/local/lib/python3.12/dist-packages (from imageio->vectorbt) (11.3.0) Requirement already satisfied: contourpy>=1.0.1 in /usr/local/lib/python3.12/dist-packages (from matplotlib->vectorbt) (1.3.3) Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.12/dist-packages (from matplotlib->vectorbt) (0.12.1) Requirement already satisfied: fonttools>=4.22.0 in /usr/local/lib/python3.12/dist-packages (from matplotlib->vectorbt) (4.63.0) Requirement already satisfied: kiwisolver>=1.3.1 in /usr/local/lib/python3.12/dist-packages (from matplotlib->vectorbt) (1.5.0) Requirement already satisfied: pyparsing>=2.3.1 in /usr/local/lib/python3.12/dist-packages (from matplotlib->vectorbt) (3.3.2) Requirement already satisfied: charset_normalizer<4,>=2 in /usr/local/lib/python3.12/dist-packages (from requests->vectorbt) (3.4.7) Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.12/dist-packages (from requests->vectorbt) (3.18) Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.12/dist-packages (from requests->vectorbt) (2.5.0) Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.12/dist-packages (from requests->vectorbt) (2026.5.20) Requirement already satisfied: joblib>=1.2.0 in /usr/local/lib/python3.12/dist-packages (from scikit-learn->vectorbt) (1.5.3) Requirement already satisfied: threadpoolctl>=3.1.0 in /usr/local/lib/python3.12/dist-packages (from scikit-learn->vectorbt) (3.6.0) Requirement already satisfied: debugpy>=1.0 in /usr/local/lib/python3.12/dist-packages (from ipykernel>=4.5.1->ipywidgets>=7.0.0->vectorbt) (1.8.15) Requirement already satisfied: jupyter-client>=6.1.12 in /usr/local/lib/python3.12/dist-packages (from ipykernel>=4.5.1->ipywidgets>=7.0.0->vectorbt) (7.4.9) Requirement already satisfied: matplotlib-inline>=0.1 in /usr/local/lib/python3.12/dist-packages (from ipykernel>=4.5.1->ipywidgets>=7.0.0->vectorbt) (0.2.2) Requirement already satisfied: nest-asyncio in /usr/local/lib/python3.12/dist-packages (from ipykernel>=4.5.1->ipywidgets>=7.0.0->vectorbt) (1.6.0) Requirement already satisfied: psutil in /usr/local/lib/python3.12/dist-packages (from ipykernel>=4.5.1->ipywidgets>=7.0.0->vectorbt) (5.9.5) Requirement already satisfied: pyzmq>=17 in /usr/local/lib/python3.12/dist-packages (from ipykernel>=4.5.1->ipywidgets>=7.0.0->vectorbt) (26.2.1) Requirement already satisfied: tornado>=6.1 in /usr/local/lib/python3.12/dist-packages (from ipykernel>=4.5.1->ipywidgets>=7.0.0->vectorbt) (6.5.7) Requirement already satisfied: setuptools>=18.5 in /usr/local/lib/python3.12/dist-packages (from ipython>=4.0.0->ipywidgets>=7.0.0->vectorbt) (75.2.0) Requirement already satisfied: jedi>=0.16 in /usr/local/lib/python3.12/dist-packages (from ipython>=4.0.0->ipywidgets>=7.0.0->vectorbt) (0.20.0) Requirement already satisfied: decorator in /usr/local/lib/python3.12/dist-packages (from ipython>=4.0.0->ipywidgets>=7.0.0->vectorbt) (4.4.2) Requirement already satisfied: pickleshare in /usr/local/lib/python3.12/dist-packages (from ipython>=4.0.0->ipywidgets>=7.0.0->vectorbt) (0.7.5) Requirement already satisfied: prompt-toolkit!=3.0.0,!=3.0.1,<3.1.0,>=2.0.0 in /usr/local/lib/python3.12/dist-packages (from ipython>=4.0.0->ipywidgets>=7.0.0->vectorbt) (3.0.52) Requirement already satisfied: pygments in /usr/local/lib/python3.12/dist-packages (from ipython>=4.0.0->ipywidgets>=7.0.0->vectorbt) (2.20.0) Requirement already satisfied: backcall in /usr/local/lib/python3.12/dist-packages (from ipython>=4.0.0->ipywidgets>=7.0.0->vectorbt) (0.2.0) Requirement already satisfied: pexpect>4.3 in /usr/local/lib/python3.12/dist-packages (from ipython>=4.0.0->ipywidgets>=7.0.0->vectorbt) (4.9.0) Requirement already satisfied: notebook>=4.4.1 in /usr/local/lib/python3.12/dist-packages (from widgetsnbextension~=3.6.0->ipywidgets>=7.0.0->vectorbt) (6.5.7) Requirement already satisfied: parso<0.9.0,>=0.8.6 in /usr/local/lib/python3.12/dist-packages (from jedi>=0.16->ipython>=4.0.0->ipywidgets>=7.0.0->vectorbt) (0.8.7) Requirement already satisfied: entrypoints in /usr/local/lib/python3.12/dist-packages (from jupyter-client>=6.1.12->ipykernel>=4.5.1->ipywidgets>=7.0.0->vectorbt) (0.4) Requirement already satisfied: jupyter-core>=4.9.2 in /usr/local/lib/python3.12/dist-packages (from jupyter-client>=6.1.12->ipykernel>=4.5.1->ipywidgets>=7.0.0->vectorbt) (5.9.1) Requirement already satisfied: jinja2 in /usr/local/lib/python3.12/dist-packages (from notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.0.0->vectorbt) (3.1.6) Requirement already satisfied: argon2-cffi in /usr/local/lib/python3.12/dist-packages (from notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.0.0->vectorbt) (25.1.0) Requirement already satisfied: nbformat in /usr/local/lib/python3.12/dist-packages (from notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.0.0->vectorbt) (5.10.4) Requirement already satisfied: nbconvert>=5 in /usr/local/lib/python3.12/dist-packages (from notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.0.0->vectorbt) (7.17.1) Requirement already satisfied: Send2Trash>=1.8.0 in /usr/local/lib/python3.12/dist-packages (from notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.0.0->vectorbt) (2.1.0) Requirement already satisfied: terminado>=0.8.3 in /usr/local/lib/python3.12/dist-packages (from notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.0.0->vectorbt) (0.18.1) Requirement already satisfied: prometheus-client in /usr/local/lib/python3.12/dist-packages (from notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.0.0->vectorbt) (0.25.0) Requirement already satisfied: nbclassic>=0.4.7 in /usr/local/lib/python3.12/dist-packages (from notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.0.0->vectorbt) (1.3.3) Requirement already satisfied: ptyprocess>=0.5 in /usr/local/lib/python3.12/dist-packages (from pexpect>4.3->ipython>=4.0.0->ipywidgets>=7.0.0->vectorbt) (0.7.0) Requirement already satisfied: wcwidth in /usr/local/lib/python3.12/dist-packages (from prompt-toolkit!=3.0.0,!=3.0.1,<3.1.0,>=2.0.0->ipython>=4.0.0->ipywidgets>=7.0.0->vectorbt) (0.8.1) Requirement already satisfied: platformdirs>=2.5 in /usr/local/lib/python3.12/dist-packages (from jupyter-core>=4.9.2->jupyter-client>=6.1.12->ipykernel>=4.5.1->ipywidgets>=7.0.0->vectorbt) (4.10.0) Requirement already satisfied: notebook-shim>=0.2.3 in /usr/local/lib/python3.12/dist-packages (from nbclassic>=0.4.7->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.0.0->vectorbt) (0.2.4) Requirement already satisfied: beautifulsoup4 in /usr/local/lib/python3.12/dist-packages (from nbconvert>=5->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.0.0->vectorbt) (4.13.5) Requirement already satisfied: bleach!=5.0.0 in /usr/local/lib/python3.12/dist-packages (from bleach[css]!=5.0.0->nbconvert>=5->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.0.0->vectorbt) (6.4.0) Requirement already satisfied: defusedxml in /usr/local/lib/python3.12/dist-packages (from nbconvert>=5->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.0.0->vectorbt) (0.7.1) Requirement already satisfied: jupyterlab-pygments in /usr/local/lib/python3.12/dist-packages (from nbconvert>=5->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.0.0->vectorbt) (0.3.0) Requirement already satisfied: markupsafe>=2.0 in /usr/local/lib/python3.12/dist-packages (from nbconvert>=5->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.0.0->vectorbt) (3.0.3) Requirement already satisfied: mistune<4,>=2.0.3 in /usr/local/lib/python3.12/dist-packages (from nbconvert>=5->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.0.0->vectorbt) (3.2.1) Requirement already satisfied: nbclient>=0.5.0 in /usr/local/lib/python3.12/dist-packages (from nbconvert>=5->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.0.0->vectorbt) (0.10.4) Requirement already satisfied: pandocfilters>=1.4.1 in /usr/local/lib/python3.12/dist-packages (from nbconvert>=5->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.0.0->vectorbt) (1.5.1) Requirement already satisfied: fastjsonschema>=2.15 in /usr/local/lib/python3.12/dist-packages (from nbformat->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.0.0->vectorbt) (2.21.2) Requirement already satisfied: jsonschema>=2.6 in /usr/local/lib/python3.12/dist-packages (from nbformat->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.0.0->vectorbt) (4.26.0) Requirement already satisfied: argon2-cffi-bindings in /usr/local/lib/python3.12/dist-packages (from argon2-cffi->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.0.0->vectorbt) (25.1.0) Requirement already satisfied: webencodings in /usr/local/lib/python3.12/dist-packages (from bleach!=5.0.0->bleach[css]!=5.0.0->nbconvert>=5->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.0.0->vectorbt) (0.5.1) Requirement already satisfied: tinycss2>=1.1.0 in /usr/local/lib/python3.12/dist-packages (from bleach[css]!=5.0.0->nbconvert>=5->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.0.0->vectorbt) (1.5.1) Requirement already satisfied: attrs>=22.2.0 in /usr/local/lib/python3.12/dist-packages (from jsonschema>=2.6->nbformat->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.0.0->vectorbt) (26.1.0) Requirement already satisfied: jsonschema-specifications>=2023.03.6 in /usr/local/lib/python3.12/dist-packages (from jsonschema>=2.6->nbformat->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.0.0->vectorbt) (2025.9.1) Requirement already satisfied: referencing>=0.28.4 in /usr/local/lib/python3.12/dist-packages (from jsonschema>=2.6->nbformat->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.0.0->vectorbt) (0.37.0) Requirement already satisfied: rpds-py>=0.25.0 in /usr/local/lib/python3.12/dist-packages (from jsonschema>=2.6->nbformat->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.0.0->vectorbt) (2026.5.1) Requirement already satisfied: jupyter-server<3,>=1.8 in /usr/local/lib/python3.12/dist-packages (from notebook-shim>=0.2.3->nbclassic>=0.4.7->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.0.0->vectorbt) (2.18.2) Requirement already satisfied: cffi>=1.0.1 in /usr/local/lib/python3.12/dist-packages (from argon2-cffi-bindings->argon2-cffi->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.0.0->vectorbt) (2.0.0) Requirement already satisfied: soupsieve>1.2 in /usr/local/lib/python3.12/dist-packages (from beautifulsoup4->nbconvert>=5->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.0.0->vectorbt) (2.8.4) Requirement already satisfied: pycparser in /usr/local/lib/python3.12/dist-packages (from cffi>=1.0.1->argon2-cffi-bindings->argon2-cffi->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.0.0->vectorbt) (3.0) Requirement already satisfied: anyio>=3.1.0 in /usr/local/lib/python3.12/dist-packages (from jupyter-server<3,>=1.8->notebook-shim>=0.2.3->nbclassic>=0.4.7->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.0.0->vectorbt) (4.13.0) Requirement already satisfied: jupyter-events>=0.11.0 in /usr/local/lib/python3.12/dist-packages (from jupyter-server<3,>=1.8->notebook-shim>=0.2.3->nbclassic>=0.4.7->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.0.0->vectorbt) (0.12.1) Requirement already satisfied: jupyter-server-terminals>=0.4.4 in /usr/local/lib/python3.12/dist-packages (from jupyter-server<3,>=1.8->notebook-shim>=0.2.3->nbclassic>=0.4.7->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.0.0->vectorbt) (0.5.4) Requirement already satisfied: websocket-client>=1.7 in /usr/local/lib/python3.12/dist-packages (from jupyter-server<3,>=1.8->notebook-shim>=0.2.3->nbclassic>=0.4.7->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.0.0->vectorbt) (1.9.0) Requirement already satisfied: python-json-logger>=2.0.4 in /usr/local/lib/python3.12/dist-packages (from jupyter-events>=0.11.0->jupyter-server<3,>=1.8->notebook-shim>=0.2.3->nbclassic>=0.4.7->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.0.0->vectorbt) (4.1.0) Requirement already satisfied: pyyaml>=5.3 in /usr/local/lib/python3.12/dist-packages (from jupyter-events>=0.11.0->jupyter-server<3,>=1.8->notebook-shim>=0.2.3->nbclassic>=0.4.7->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.0.0->vectorbt) (6.0.3) Requirement already satisfied: rfc3339-validator in /usr/local/lib/python3.12/dist-packages (from jupyter-events>=0.11.0->jupyter-server<3,>=1.8->notebook-shim>=0.2.3->nbclassic>=0.4.7->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.0.0->vectorbt) (0.1.4) Requirement already satisfied: rfc3986-validator>=0.1.1 in /usr/local/lib/python3.12/dist-packages (from jupyter-events>=0.11.0->jupyter-server<3,>=1.8->notebook-shim>=0.2.3->nbclassic>=0.4.7->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.0.0->vectorbt) (0.1.1) Requirement already satisfied: fqdn in /usr/local/lib/python3.12/dist-packages (from jsonschema[format-nongpl]>=4.18.0->jupyter-events>=0.11.0->jupyter-server<3,>=1.8->notebook-shim>=0.2.3->nbclassic>=0.4.7->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.0.0->vectorbt) (1.5.1) Requirement already satisfied: isoduration in /usr/local/lib/python3.12/dist-packages (from jsonschema[format-nongpl]>=4.18.0->jupyter-events>=0.11.0->jupyter-server<3,>=1.8->notebook-shim>=0.2.3->nbclassic>=0.4.7->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.0.0->vectorbt) (20.11.0) Requirement already satisfied: jsonpointer>1.13 in /usr/local/lib/python3.12/dist-packages (from jsonschema[format-nongpl]>=4.18.0->jupyter-events>=0.11.0->jupyter-server<3,>=1.8->notebook-shim>=0.2.3->nbclassic>=0.4.7->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.0.0->vectorbt) (3.1.1) Requirement already satisfied: rfc3987-syntax>=1.1.0 in /usr/local/lib/python3.12/dist-packages (from jsonschema[format-nongpl]>=4.18.0->jupyter-events>=0.11.0->jupyter-server<3,>=1.8->notebook-shim>=0.2.3->nbclassic>=0.4.7->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.0.0->vectorbt) (1.1.0) Requirement already satisfied: uri-template in /usr/local/lib/python3.12/dist-packages (from jsonschema[format-nongpl]>=4.18.0->jupyter-events>=0.11.0->jupyter-server<3,>=1.8->notebook-shim>=0.2.3->nbclassic>=0.4.7->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.0.0->vectorbt) (1.3.0) Requirement already satisfied: webcolors>=24.6.0 in /usr/local/lib/python3.12/dist-packages (from jsonschema[format-nongpl]>=4.18.0->jupyter-events>=0.11.0->jupyter-server<3,>=1.8->notebook-shim>=0.2.3->nbclassic>=0.4.7->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.0.0->vectorbt) (25.10.0) Requirement already satisfied: lark>=1.2.2 in /usr/local/lib/python3.12/dist-packages (from rfc3987-syntax>=1.1.0->jsonschema[format-nongpl]>=4.18.0->jupyter-events>=0.11.0->jupyter-server<3,>=1.8->notebook-shim>=0.2.3->nbclassic>=0.4.7->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.0.0->vectorbt) (1.3.1) Requirement already satisfied: arrow>=0.15.0 in /usr/local/lib/python3.12/dist-packages (from isoduration->jsonschema[format-nongpl]>=4.18.0->jupyter-events>=0.11.0->jupyter-server<3,>=1.8->notebook-shim>=0.2.3->nbclassic>=0.4.7->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets>=7.0.0->vectorbt) (1.4.0)
2. Library Imports
This section imports all required Python libraries and modules. It also includes configuration for suppressing warnings to ensure cleaner output.
import warnings
warnings.filterwarnings("ignore") # Suppress warnings for cleaner output
import pandas as pd # Data manipulation and analysis
import numpy as np # Numerical operations
import vectorbt as vbt # High-performance backtesting library
import plotly.graph_objects as go # Interactive charting library
from plotly.subplots import make_subplots # For creating subplots in Plotly figures3. Understanding vectorbt
vectorbt is a robust Python library designed for high-performance portfolio backtesting, leveraging numpy and pandas for efficient computation. Its core strength lies in evaluating thousands of parameter combinations simultaneously through vectorized array operations, making it ideal for parameter optimization and strategy screening.
Key Features:
| Feature | Description |
|---|---|
| Vectorized Computation | Entire backtest logic executed via array operations, eliminating Python loops for speed. |
| Parameter Sweeps | Simultaneously test all combinations of parameters in a single function call. |
| Built-in Indicators | Access to over 100 pre-built technical indicators, including SMA, EMA, RSI, and MACD. |
| Portfolio Simulation | Comprehensive simulation capabilities, including fees, slippage, position sizing, and cash management. |
| Performance Analytics | Integrated metrics such as Sharpe Ratio, Sortino Ratio, Calmar Ratio, drawdown analysis, and detailed trade statistics. |
| Interactive Plotting | Plotly-based charts for visualizing equity curves, trade markers, and parameter heatmaps. |
When to Use vectorbt vs. Event-Driven Backtesters:
vectorbt: Optimal for rapid parameter optimization, signal screening, and fast iteration during the research and development phases of a strategy.- Event-Driven (e.g., as explored in Notebook 67): Preferred for final performance validation, detailed and realistic execution modeling, and development of live trading systems due to its granular control over events.
4. Data Generation
This section focuses on generating synthetic financial time series data to serve as input for the backtesting process. A custom function, generate_data, is defined to create a DataFrame resembling candlestick data (open, high, low, close) along with volume, for a specified number of periods. The generated close prices are then converted into a pandas.Series with a DatetimeIndex, which is the preferred format for vectorbt compatibility.
def generate_data(periods: int) -> pd.DataFrame:
"""Generates synthetic OHLCV (Open, High, Low, Close, Volume) data."""
start_date = pd.to_datetime("2024-01-01 00:00:00+00:00")
datetime_index = pd.date_range(start_date, periods=periods, freq="1min", tz="UTC")
price_data = []; last_close = 42000
volatility_scale = 0.005; wick_scale = 0.002
for _ in range(periods):
# Simulate open and close prices with some volatility
open_price = last_close + np.random.normal(0, last_close * volatility_scale * 0.1)
close_price = open_price + np.random.normal(0, last_close * volatility_scale)
# Determine body high/low and then add wicks
body_high = max(open_price, close_price)
body_low = min(open_price, close_price)
high_price = max(body_high + abs(np.random.normal(0, last_close * wick_scale)),
open_price, close_price)
low_price = min(body_low - abs(np.random.normal(0, last_close * wick_scale)),
open_price, close_price)
# Ensure high is never less than low
if high_price < low_price:
high_price, low_price = low_price, high_price
price_data.append({
"open": max(1, int(open_price)),
"high": max(1, int(high_price)),
"low": max(1, int(low_price)),
"close": max(1, int(close_price)),
})
last_close = close_price # Update last_close for the next period
df = pd.DataFrame(price_data, index=datetime_index)
df.index.name = "datetime"
df["volume"] = np.random.uniform(100.0, 500.0, periods) # Simulate volume data
df["datetime"] = df.index.to_series() # Add datetime column for plotting convenience
return df.reset_index(drop=True)
df = generate_data(500) # Generate 500 periods of data
# Convert the 'close' column to an indexed Series for vectorbt compatibility.
# `vectorbt` indicators and portfolio functions typically expect a pandas Series with a DatetimeIndex.
close_series = pd.Series(
df["close"].values,
index=pd.DatetimeIndex(df["datetime"]),
name="close", # Name the series 'close' for clarity
)
display(df.head()) # Display the first few rows of the generated DataFrame
print(f"Series length: {len(close_series)}") # Print the length of the close series| open | high | low | close | volume | datetime | |
|---|---|---|---|---|---|---|
| 0 | 42014 | 42326 | 41970 | 42314 | 449.783093 | 2024-01-01 00:00:00+00:00 |
| 1 | 42345 | 42476 | 42020 | 42026 | 199.268131 | 2024-01-01 00:01:00+00:00 |
| 2 | 42003 | 42101 | 41996 | 42063 | 483.272336 | 2024-01-01 00:02:00+00:00 |
| 3 | 42103 | 42203 | 41617 | 41797 | 304.232952 | 2024-01-01 00:03:00+00:00 |
| 4 | 41802 | 42045 | 41762 | 41966 | 450.774516 | 2024-01-01 00:04:00+00:00 |
Series length: 500
5. Single-Parameter Backtest
This section demonstrates a basic backtest using a simple Moving Average (MA) crossover strategy with fixed parameters. It illustrates how to compute indicators, generate entry and exit signals, and simulate a portfolio using vectorbt's core functionalities. The results are then summarized through comprehensive performance statistics.
# --- Compute moving averages using vectorbt's built-in indicator engine ---
# `vbt.MA.run` calculates the Simple Moving Average (SMA) for the given 'close_series'.
# `window=10` specifies a 10-period SMA for the fast moving average.
fast_ma = vbt.MA.run(close_series, window=10)
# `window=30` specifies a 30-period SMA for the slow moving average.
slow_ma = vbt.MA.run(close_series, window=30)
# --- Generate entry and exit signals ---
# Entries occur when the fast MA crosses above the slow MA (bullish signal).
entries = fast_ma.ma_crossed_above(slow_ma)
# Exits occur when the fast MA crosses below the slow MA (bearish signal).
exits = fast_ma.ma_crossed_below(slow_ma)
# --- Build and run portfolio simulation ---
# `vbt.Portfolio.from_signals` creates a portfolio based on the generated entry/exit signals.
# `close_series` provides the asset prices for trade execution.
# `init_cash` sets the starting capital for the portfolio.
# `fees` applies a transaction cost per trade (0.1% in this case).
# `freq='1min'` specifies the data frequency, crucial for annualizing performance metrics.
portfolio = vbt.Portfolio.from_signals(
close_series,
entries,
exits,
init_cash = 10_000,
fees = 0.001, # 0.1% per trade (round-trip = 0.2%)
freq = "1min",
)
print("--- vectorbt Portfolio Statistics ---")
# `portfolio.stats()` generates a detailed report of the portfolio's performance metrics.
print(portfolio.stats())--- vectorbt Portfolio Statistics --- Start 2024-01-01 00:00:00+00:00 End 2024-01-01 08:19:00+00:00 Period 0 days 08:20:00 Start Value 10000.0 End Value 11451.662237 Total Return [%] 14.516622 Benchmark Return [%] 18.022404 Max Gross Exposure [%] 100.0 Total Fees Paid 203.163248 Max Drawdown [%] 4.547096 Max Drawdown Duration 0 days 02:42:00 Total Trades 10 Total Closed Trades 10 Total Open Trades 0 Open Trade PnL 0.0 Win Rate [%] 60.0 Best Trade [%] 10.639111 Worst Trade [%] -1.580561 Avg Winning Trade [%] 3.083394 Avg Losing Trade [%] -1.054615 Avg Winning Trade Duration 0 days 00:41:20 Avg Losing Trade Duration 0 days 00:17:45 Profit Factor 4.460934 Expectancy 145.166224 Sharpe Ratio 53.016368 Calmar Ratio 1678281373142382224283974209531393359708152511... Omega Ratio 1.257145 Sortino Ratio 80.497781 dtype: object
Explanation of Key Components:
-
vbt.MA.run(close_series, window=X): This function computes the Moving Average usingvectorbt's optimized indicator engine. It returns avectorbtindicator object that inherently supports advanced operations like crossover detection. -
ma_crossed_above(slow_ma): This method, available on the indicator object, generates a booleanSerieswhereTrueindicates the exact timestamp when the fast Moving Average crosses above the slow Moving Average. This is equivalent to the condition(fast > slow) & (fast.shift(1) <= slow.shift(1)), signifying a bullish signal. -
ma_crossed_below(slow_ma): Similar toma_crossed_above, this method identifies the exact timestamps where the fast Moving Average crosses below the slow Moving Average, signaling a bearish entry or an exit. -
vbt.Portfolio.from_signals(close_series, entries, exits, ...): This is the core portfolio simulator withinvectorbt. It takes the asset priceSeriesand the boolean entry/exit signalSeriesas primary inputs. It systematically manages capital, applies user-defined fees, tracks the state of positions, and processes all trading logic in a single, vectorized pass. Thefreqparameter is essential for correctly annualizing various performance metrics. -
portfolio.stats(): This method provides a comprehensive output of performance statistics for the simulated portfolio. Key metrics include total return, Sharpe ratio, maximum drawdown, win rate, and the total number of trades executed, offering a complete overview of the strategy's performance.
6. Parameter Optimization
This section demonstrates vectorbt's powerful capability for multi-parameter optimization. Instead of running individual backtests in a loop, vectorbt allows for simultaneously evaluating all combinations of a given set of parameters. This approach significantly speeds up the process of identifying optimal parameter sets for a trading strategy.
# --- Multi-parameter sweep: test all combinations of fast and slow moving average windows ---
# Define a list of window sizes for the fast moving average.
fast_windows = [5, 10, 15, 20]
# Define a list of window sizes for the slow moving average.
slow_windows = [20, 30, 40, 50]
# Run MA indicator for all fast window combinations. `short_name="fast"` labels the columns.
fast_ma_multi = vbt.MA.run(close_series, window=fast_windows, short_name="fast")
# Run MA indicator for all slow window combinations. `short_name="slow"` labels the columns.
slow_ma_multi = vbt.MA.run(close_series, window=slow_windows, short_name="slow")
# Generate entries: when any fast MA crosses above any slow MA.
entries_multi = fast_ma_multi.ma_crossed_above(slow_ma_multi)
# Generate exits: when any fast MA crosses below any slow MA.
exits_multi = fast_ma_multi.ma_crossed_below(slow_ma_multi)
# Build and run portfolios for all parameter combinations.
# `init_cash`, `fees`, and `freq` are applied to each simulated portfolio.
portfolio_multi = vbt.Portfolio.from_signals(
close_series,
entries_multi,
exits_multi,
init_cash = 10_000,
fees = 0.001,
freq = "1min",
)
# Extract and display the total return for each parameter combination.
# The result is a multi-indexed Series, which is unstacked for better readability as a matrix.
returns_matrix = portfolio_multi.total_return()
print("--- Total Return Matrix (Fast Window × Slow Window) ---")
display(returns_matrix.unstack())--- Total Return Matrix (Fast Window × Slow Window) ---
| slow_window | 20 | 30 | 40 | 50 |
|---|---|---|---|---|
| fast_window | ||||
| 5 | 0.060002 | NaN | NaN | NaN |
| 10 | NaN | 0.145166 | NaN | NaN |
| 15 | NaN | NaN | 0.148511 | NaN |
| 20 | NaN | NaN | NaN | 0.086075 |
Explanation:
vectorbt excels at parameter optimization by evaluating all N parameter combinations (in this example, 4 fast MA windows × 4 slow MA windows = 16 combinations) simultaneously within a single, highly optimized function call. This vectorized approach eliminates the need for explicit loops, which would typically involve running 16 separate backtests in a traditional, loop-based framework.
The output is a matrix where each cell represents the total return achieved by a specific pairing of fast and slow moving average windows. This capability significantly streamlines the process of identifying the most performant parameter configurations for a given trading strategy, making vectorbt an indispensable tool for quantitative research and strategy development.
7. Visualization
This section demonstrates how to visualize the backtest results using plotly, an interactive charting library. It generates a multi-panel plot showcasing the asset price with moving averages and trade signals, alongside the portfolio's equity curve. This visualization provides a clear understanding of strategy performance and trade execution.
# Create a subplot figure with two rows and shared x-axes for time alignment.
# The top subplot is for price and indicators, the bottom for the equity curve.
fig = make_subplots(
rows=2, cols=1, shared_xaxes=True,
subplot_titles=[
"Price + MA Crossover + Entry/Exit Signals", # Title for the top subplot
"vectorbt Equity Curve", # Title for the bottom subplot
],
row_heights=[0.55, 0.45], # Allocate more height to the price chart
)
# Add candlestick chart to the top subplot.
# This visualizes the open, high, low, and close prices over time.
fig.add_trace(go.Candlestick(
x=df["datetime"],
open=df["open"], high=df["high"],
low=df["low"], close=df["close"],
name="Price"), row=1, col=1)
# Add the Fast Moving Average (10 periods) to the top subplot.
fig.add_trace(go.Scatter(
x=close_series.index, y=fast_ma.ma.values,
mode="lines", name="Fast MA (10)",
line=dict(color="blue", width=1)), row=1, col=1)
# Add the Slow Moving Average (30 periods) to the top subplot.
fig.add_trace(go.Scatter(
x=close_series.index, y=slow_ma.ma.values,
mode="lines", name="Slow MA (30)",
line=dict(color="orange", width=1)), row=1, col=1)
# Define buy and sell signal masks from the entries and exits Series
buy_signals_mask = entries.loc[entries].index
sell_signals_mask = exits.loc[exits].index
# Filter the close series to get prices only at buy signal times.
buy_prices = close_series.loc[buy_signals_mask]
# Filter the close series to get prices only at sell signal times.
sell_prices = close_series.loc[sell_signals_mask]
# Add 'Buy' markers (green triangles pointing up) to the top subplot.
# Multiplied by 0.999 to place them slightly below the close price for visibility.
fig.add_trace(go.Scatter(
x=buy_prices.index,
y=buy_prices.values * 0.999,
mode="markers",
marker=dict(symbol="triangle-up", size=10, color="green"),
name="Buy Signal"), row=1, col=1)
# Add 'Sell' markers (red triangles pointing down) to the top subplot.
# Multiplied by 1.001 to place them slightly above the close price for visibility.
fig.add_trace(go.Scatter(
x=sell_prices.index,
y=sell_prices.values * 1.001,
mode="markers",
marker=dict(symbol="triangle-down", size=10, color="red"),
name="Sell Signal"), row=1, col=1)
# Get the portfolio's equity curve values.
equity_values = portfolio.value()
# Add the portfolio equity curve to the bottom subplot.
fig.add_trace(go.Scatter(
x=equity_values.index, y=equity_values.values,
mode="lines", name="Portfolio Value ($)",
line=dict(color="green", width=2)), row=2, col=1)
# Update layout settings for the entire figure.
fig.update_layout(
title_text="vectorbt Backtest — MA Crossover Strategy", # Main title for the figure
xaxis_rangeslider_visible=False, # Hide the range slider at the bottom of the x-axis
height=800, # Set the overall height of the figure
yaxis=dict(autorange=True), # Auto-scale the y-axis for the price chart
xaxis2_title="Datetime", # Label for the shared x-axis (bottom)
yaxis_title="Price", # Label for the y-axis of the top subplot
yaxis2_title="Portfolio Value ($)", # Label for the y-axis of the bottom subplot
)
fig.show() # Display the generated interactive plot8. Conclusion
This notebook provided a comprehensive introduction to vectorbt, a powerful Python library for high-performance backtesting of quantitative trading strategies. We covered:
- Dependency Installation & Library Imports: Setting up the environment and importing essential libraries.
- Understanding
vectorbt: A detailed overview of its core features, including vectorized computation, parameter sweeps, built-in indicators, and performance analytics. - Data Generation: Creating synthetic OHLCV data suitable for backtesting.
- Single-Parameter Backtest: Demonstrating a basic Moving Average crossover strategy, including signal generation and portfolio simulation.
- Parameter Optimization: Showcasing
vectorbt's ability to efficiently evaluate multiple parameter combinations simultaneously, streamlining strategy research. - Visualization: Generating interactive plots to visualize price action, trade signals, and portfolio equity curves.
vectorbt stands out as an invaluable tool for researchers and quantitative traders due to its focus on speed and efficiency, particularly for parameter optimization and initial strategy screening. By leveraging vectorized operations, it significantly reduces the time required to iterate on ideas and identify promising strategy parameters, making it an excellent complement to more granular event-driven backtesters for later-stage validation.