You've successfully subscribed to Alpaca Learn - Developer API Trading Tutorials, Code Samples
Great! Next, complete checkout for full access to Alpaca Learn - Developer API Trading Tutorials, Code Samples
Welcome back! You've successfully signed in.
Success! Your account is fully activated, you now have access to all content.
Success! Your billing info is updated.
Billing info update failed.

Introduction to Backtesting with VectorBT

Rahul Chowdhury
Rahul Chowdhury

Vectorbt is a backtesting library for Python. It allows you to quickly and easily backtest strategies in only a few lines of code. Vectorbt was developed to address some of the performance shortcomings of other backtesting libraries. It excels at processing large amounts of data. By representing strategy data as numpy arrays, it takes advantage of the fast computation speeds numpy offers for vectorized operations. This allows for testing hundreds of variations of strategies relatively quickly.

Alpaca's Market Data can be accessed through Vectorbt. Alpaca's Market Data along with Vectorbt allows you to backtest over 5+ years of historical data across thousands of US stocks and cryptocurrencies.

Accessing Historical Data

Before we get started, you’ll need to install vectorbt. This can be done using pip.

pip install vectorbt

Vectorbt provides equity and crypto data through various data providers.

Alpaca is one of the data providers integrated with vectorbt. To access Alpaca data, you’ll need to first set your API keys within the vectorbt settings.

import vectorbt as vbt['alpaca']['key_id'] = 'Your API Key'['alpaca']['secret_key'] = 'Your Secret Key'

Now we can start accessing data through Alpaca. We can access both equity and crypto data through vectorbt. Data is retrieved using the Download method. One of vectorbt’s unique features is the ability to define times in a variety of ways. In addition to defining absolute dates such as 2021-03-11 UTC, we can define relative dates such as a start time of 4 days ago UTC and end time of 1 day ago UTC. We can also provide a timeframe we’d like our data to be resolved at like 15m, which tells vectorbt that we want 15 minute bars.

alpacadata = vbt.AlpacaData.Download(symbol='AAPL', start='4 days ago UTC`, end=`1 day ago UTC`, timeframe='1h')


#                            Open      High       Low     Close      Volume
# timestamp
# 2021-12-23 14:00:00+00:00  177.0500  177.0500  177.0500  177.0500    1967
# 2021-12-23 15:00:00+00:00  177.0500  177.0500  177.0300  177.0500    3218
# ...                            ...       ...       ...       ...     ...
# 2021-12-27 15:00:00+00:00  178.0000  178.0079  177.9311  177.9710  106395
# 2021-12-27 16:00:00+00:00  177.9700  178.0564  177.9430  177.9600  153325

# [105 rows x 5 columns]

SIP Data

The free market data plan limits the historical data you can request. With the free plan you aren't able to query data from within the past 15 minutes and the data is limited to only IEX. On the other hand, with a premium market data subscription, you can access data from all US exchanges and there are no limits on the historical data you can query. If your API keys are associated with an account with a premium market data subscription, you will automatically be able to access unlimited data in your historical data calls.

alpacadata = vbt.AlpacaData.Download(symbol='GME', 
start='4 hours ago UTC`, end=`now UTC`, timeframe='1h')


Running Backtests

Simple Moving Average Crossover

Let’s backtest a simple moving average crossover strategy; buy when the 10-day moving average crosses above the 20-day moving average, and sell when opposite. For this, we are going to use MA class for calculating moving averages and generating signals.

fast_ma =, 10, short_name='fast')
slow_ma =, 20, short_name='slow')

entries = fast_ma.ma_crossed_above(slow_ma)
# Date
# 2019-01-01 00:00:00+00:00    False
# 2019-01-02 00:00:00+00:00    False
# 2019-01-03 00:00:00+00:00    False
# ...                            ...
# 2019-12-30 00:00:00+00:00    False
# Freq: D, Length: 366, dtype: bool

We can calculate when our strategy exits using the ma_crossed_below method.

exits = fast_ma.ma_crossed_below(slow_ma)

# Date
# 2019-01-01 00:00:00+00:00    False
# 2019-01-02 00:00:00+00:00    False
# 2019-01-03 00:00:00+00:00    False
# . ..                           ...
# 2019-12-30 00:00:00+00:00    False
# 2019-12-31 00:00:00+00:00    False
# 2020-01-01 00:00:00+00:00    False
# Freq: D, Length: 366, dtype: bool

Finally our portfolio return is calculated by passing in the signals we computed earlier and the price of AAPL.

pf = vbt.Portfolio.from_signals(alpacadata, entries, exits)

# 0.636680693047752

Optimizing Parameters

The real power of vectorbt arises when looking at variations of a strategy. Vectorbt makes it fast and easy to test how changes in parameters affect performance. For example, let’s say we wanted to test how performance of our strategy compares when trading AAPL against BTCUSD, and when changing our moving average slow and fast periods.

alpacadata = vbt.AlpacaData.Download(symbol=['AAPL', “BTCUSD”], start='4 days ago UTC`, end=`1 day ago UTC`, timeframe='1h')

fast_ma =, [10, 20], short_name='fast')
slow_ma =, [30, 30], short_name='slow')

We can calculate the entries and exits as we did before and then calculate the difference in portfolio performance.

entries = fast_ma.ma_crossed_above(slow_ma)
exits = fast_ma.ma_crossed_below(slow_ma)

pf = vbt.Portfolio.from_signals(alpacadata, entries, exits)


# fast_window  slow_window  symbol
# 10           30           AAPL       0.848840
#                          BTCUSD       0.244204
# 20           30           AAPL       0.543411
#                          BTCUSD      -0.319102


Vectorbt is a blazingly fast backtrading library. It allows you to not only backtest your strategy, but also optimize its parameters quickly. Check out the vectorbt documentation for more information.

All investments involve risk and the past performance of a security, or financial product does not guarantee future results or returns. Keep in mind that while diversification may help spread risk it does not assure a profit, or protect against loss, in a down market. There is always the potential of losing money when you invest in securities, or other financial products. Investors should consider their investment objectives and risks carefully before investing.

Cryptocurrency is highly speculative in nature, involves a high degree of risks, such as volatile market price swings, market manipulation, flash crashes, and cybersecurity risks. Cryptocurrency is not regulated or is lightly regulated in most countries. Cryptocurrency trading can lead to large, immediate and permanent loss of financial value. You should have appropriate knowledge and experience before engaging in cryptocurrency trading. For additional information please click here.

Alpaca does not prepare, edit, or endorse Third Party Content. Alpaca does not guarantee the accuracy, timeliness, completeness or usefulness of Third Party Content, and is not responsible or liable for any content, advertising, products, or other materials on or available from third party sites.

Securities brokerage services are provided by Alpaca Securities LLC ("Alpaca Securities"), member FINRA/SIPC, a wholly-owned subsidiary of AlpacaDB, Inc. Technology and services are offered by AlpacaDB, Inc.

Cryptocurrency services are provided by Alpaca Crypto LLC ("Alpaca Crypto"), a wholly-owned subsidiary of AlpacaDB, Inc. Alpaca Crypto is not a member of SIPC or FINRA. Cryptocurrencies are not stocks and your cryptocurrency investments are not protected by either FDIC or SIPC.

This is not an offer, solicitation of an offer, or advice to buy or sell securities or cryptocurrencies, or open a brokerage account or cryptocurrency account in any jurisdiction where Alpaca Securities or Alpaca Crypto respectively, are not registered.

BacktestingMarket Data APIPython

Rahul Chowdhury

I'm a software engineer at Alpaca working to make our developers' lives easier. Previously I worked at QuantConnect where I built many algorithmic trading strategies.