Author:

To recommend a backtesting library, I considered many relevant aspects when choosing any library. Not only did I consider how mature each project is, but also the extent to which the repository is being maintained. Additionally, having up-to-date documentation, in addition to multiple guides and tutorials, is also beneficial for getting started in using any library.

Having said that, I also considered the main specific features that a backtesting framework should provide, such as the speed of execution and the number and flexibility of the features that are available.

Both VectorBT and Backtesting.Py are the best backtesting libraries in Python that are currently available. VectorBT is especially useful for performing thousands of iterations incredibly fast, whereas Backtesting.Py is a very intuitive and mature library. Both projects are being actively maintained and have a thriving community of users providing constant feedback and creating content and tutorials.

In the following sections, I will go into further detail regarding the recommended libraries. Additionally, I’ll provide an exhaustive list of other reliable backtesting framework that you can use if either of the recommended projects doesn’t suit your specific requirements.

If you’re unsure whether you should instead create your own backtester, look at this article I wrote, where I go through the main pros and cons of doing so.

Last but not least, if you’re not a proficient Python programmer, it is worth mentioning that you’ll probably be able to backtest much more efficiently using BacktestXL. This backtesting engine works natively in Microsoft Excel and also fetches historical stock prices, and alternative datasets. It also calculates technical indicators and has pattern recognition functions. Disclaimer: we’re the developers, but it really is the software we use for our personal research!

List of Backtesting Libraries for Python

In this section, I provide a list of the most relevant backtesting frameworks in Python. I chose not to add libraries that did not have a minimum threshold of features, active users, documentation, and resources.

The following table condenses the critical aspects of each library:

LibraryEase of use# FeaturesProcessing SpeedCommunity ActivityProject ActivityDocumentationScoreWebsite
AlephNullHighLowLowNoneNonePoorLink
Backtesting.pyHighHighMediumHighMediumHigh⭐⭐⭐⭐⭐Link
BacktraderHighHighLowHighLowHigh⭐⭐⭐⭐Link
btLowMediumLowMediumLowMedium⭐⭐Link
PyAlgotradeMediumLowLowNoneNonePoorLink
PyBacktestLowLowMediumLowNonePoorLink
VectorBTMediumHighHighHighHighHigh⭐⭐⭐⭐⭐Link
ZiplineMediumMediumLowMediumNoneMedium⭐⭐⭐Link
Features of the most popular Python Backtesting Libraries

VectorBT: fastest backtesting library

The fastest python library for backtesting trading strategies is VectorBT. Even though it is a vector-based engine, VectorBT has the advantage of incorporating recursive features, such as trailing stop losses, which are commonly unavailable on these backtesters.

It is currently being actively developed, although new features are only available in its Pro version. The subscription is relatively cheap as of writing the article, but it is worth mentioning that it is the only python backtesting framework with features behind a paywall.

The main drawback of VectorBT is its very opinionated syntax, which makes it somewhat challenging to get used to the library. Luckily, its developers and users have created lots of online guides, tutorials, and resources that cover a broad range of topics.

The following tutorial covers a lot of features available on VectorBT’s free version:

Advantages

  • Fastest library available
  • Excellent documentation
  • Active community
  • Plenty of guides and tutorials are available
  • Integration with TA-Lib and Pandas-TA

Disadvantages

  • New features are only available for the Pro version
  • Opinionated and less intuitive syntax
  • Vector-based approach makes it challenging to implement strategies that have recursive features

Backtesting.py: easiest backtesting library

Although defining which library is the easiest to get started is subjective, Backtesting.py is, by most standards, the answer. Due to its event-driven approach, it features an intuitive structure that helps translate trading strategies into code.

Backtesting.py features lots of useful functionalities, such as working with multiple time frames, easily doing parameter optimization, creating composable strategies, and quickly testing machine learning-based strategies.

Being an event-driven backtester, shipping a strategy from Backtesting.py to a live trading environment is easier to do than on vector-based backtesting engines.

The main disadvantage of Backtesting.Py is the impossibility of backtesting strategies with multiple assets at once. Due to this, you won’t be able to test portfolio rebalancing strategies. Having said that, you’ll still be able to backtest pairs trading strategies if you express an asset’s price in terms of the other.

This video I created goes through a simple strategy to get started using this library:

Advantages

  • Intuitive and easy to get started
  • Excellent documentation
  • Active community
  • Plenty of guides and tutorials are available
  • Event-Driven structure allows for recursive features, such as trailing-stop-losses
  • Integration with TA-Lib and Pandas-TA

Disadvantages

  • Slower execution when compared to vector-based backtesters
  • Not possible to test portfolios or multi-asset strategies

AlephNull

Aleph null is an obsolete and unmaintained backtesting module that also allows for executing algorithmic trading strategies. The project was built on top of Zipline, the open-source project that powered the now-defunct platform Quantopian.

Advantages

  • Intuitive event-driven approach

Disadvantages

  • No new features are being added
  • No active community behind it
  • Completely obsolete when compared to newer projects

Conclusion: Not recommended

Backtrader

Backtrader is an excellent event-based backtesting framework that is easy to use and has a rich set of features available for practitioners to test their strategies. Its active community, good documentation, and excellent tutorials make Backtrader a solid alternative to Backtesting.py. Its only disadvantage is the lack of activity in the GitHub project.

Advantages

  • Plenty of tutorials and guides are available
  • Allows for testing multi-asset strategies
  • Integration with ta-lib for technical indicators
  • Very active community
  • Featured in academic papers and books

Disadvantages

  • Note being currently maintained nor developed

Conclusion: a solid alternative to Backtesting.py

Bt

Bt is an event-driven backtesting engine that is easy to get started and very convenient for testing portfolio strategies. Having said that, its opinionated syntax makes it challenging to implement custom strategies.

It also has a thriving community of active users and is still a fairly active project, although its documentation is incomplete, and there aren’t many guides and tutorials available.

Advantages

  • Easy to get started
  • Convenient for backtesting portfolios
  • Fairly active project

Disadvantages

  • Poor documentation
  • Opinionated syntax
  • Not many online resources and tutorials

Conclusion: Strong candidates. Requires more features and better documentation

Pybacktest

Pybacktest is one of the few vector-based backtesters available, making it a suitable choice for backtests where processing speed is required. Although it managed to have an active community, it is by no means a mature project, and it is not being developed any further.

It has no documentation and only provides a few insufficient examples.

If you choose a vector-based backtesting engine, definitely use VectorBT instead.

Advantages

  • Vector-based approach allows for fast computations

Disadvantages

  • Not maintained nor developed
  • Limited functionalities
  • Not a mature project
  • No documentation
  • Limited resources available

Conclusion: Not recommended

PyAlgoTrade

PyAlgoTrade is an event-driven backtester that is relatively easy to learn and even allows live trading cryptocurrencies on Bitstamp*. Due to its approach, it is similar in nature to Backtrader and Backtesting.py, but much less feature-rich.

*Disclaimer: before writing this article, I did not even know this exchange existed!

Advantages

  • Allows crypto paper and live trading on Bitstamp
  • Integrates nicely with TA-Lib

Disadvantages

  • Limited features in comparison to modern backtesters
  • Limited output metrics or charting
  • Not being currently developed nor maintained

Conclusion: Not recommended

Zipline

Zipline was the backtesting engine behind Quantopian, a crowd-sourced hedge fund that allowed users to create trading strategies similar to QuantConnect. The repository is currently not being maintained anymore since its parent company shut down in November 2020.

Although Zipline is relatively easy due to its event-driven approach, its installation is not as straightforward as one would expect from a popular project.

Since it was one of the most complete and reliable projects once, the project still has an active community of users and plenty of resources to learn from.

Advantages

  • Easy to use
  • Relatively active community
  • Plenty of online resources for learning

Disadvantages

  • The project is not currently being maintained
  • Installation is not straightforward

Conclusion: Not recommended if you don’t already know how to use it

Is python a good programming language for backtesting trading strategies?

Python is arguably the most appropriate programming language to research, backtest and implement backtesting strategies.

Not only are there reliable backtesting engines available, such as VectorBT, Backtrader, and Backtesting.py, but Python’s friendly learning curve makes it the default programming language for quickly prototyping trading strategies even with limited programming skills.

 Additionally, Python has one of the richest sets of data science, statistics, scraping, and machine learning libraries out there. These can be used for quickly getting and cleaning data and prototyping complex models. Examples of such libraries are Pandas, Numpy, SciKit-Learn, Keras, PyTorch, Tensorflow, and Scrapy, amongst many others. 

Having said that, there are other programming languages that are also very popular in the algorithmic trading industry. If you know your way around C, C++, Java, or C#, you will have no problem finding active projects related to backtesting specific tasks. Due to its wide use, there are even backtesting libraries available for Javascript.

Backtesting Examples

In this section, I will lay out a very simple long-only moving average crossover strategy, where we buy an asset whenever the 12-day moving average crosses the 24-day moving average from below. When the positive happens, we close the position (if we currently have one).

I will replicate this strategy using VectorBT and Backtesting.py, since they are the libraries I recommend using.

In order to use the same data for both strategies, I will fetch the bars from the following function:

import yfinance as yf
import pandas as pd

def get_data(ticker:str='AAPL',from_date:str='2020-01-01',to_date:str='2022-11-30',interval:str='1d') -> pd.DataFrame:
    yf_ticker = yf.Ticker(ticker)
    return yf_ticker.history(start=from_date,end=to_date,interval=interval)

Backtesting with Backtesting.py

Let’s first import the required libraries and create a function to calculate the moving average:

import backtesting as bt
from backtesting import Strategy, Backtest
from backtesting.lib import crossover
import pandas as pd

def MovingAverage(closes:pd.Series, n:int) -> pd.Series:
    return pd.Series(closes).rolling(n).mean()

The following code defines the logic of the trading strategy:

class SmaCross(Strategy):
    sma_fast = 12
    sma_slow = 24
    
    def init(self):
        self.sma1 = self.I(MovingAverage, self.data.Close, self.sma_fast)
        self.sma2 = self.I(MovingAverage, self.data.Close, self.sma_slow)

    def next(self):
        if not self.position and crossover(self.sma1, self.sma2):
            self.buy()
        elif self.position and crossover(self.sma2, self.sma1):
            self.position.close()

To run the strategy, view the statistics, and plot a few nice charts, we have to execute the following lines:

data = get_data(ticker='AAPL',from_date='2020-01-01',to_date='2022-11-30')
bt = Backtest(data, SmaCross, cash=10_000, commission=0,exclusive_orders=True)
stats = bt.run()
print(stats)
print(stats._trades)
bt.plot()
Metrics calculated using Backtesting.py
Trades generated using Backtesting.py
Plots generated with Backtesting.py

Backtesting with Vector BT

Backtesting a moving average crossover strategy can be done in fewer lines using VectorBT. Having said that, the framework is much more opinionated than Backtesting.py, and you will have to refer to the documentation quite often to do even the most straightforward backtests.

As in the previous example, let’s start by importing the required libraries and the custom-made function to fetch the data:

import vectorbt as vbt

price = data = get_data(ticker='AAPL',from_date='2020-01-01',to_date='2022-11-30')['Close']

Now we need to calculate the entries and exits and pass them to the backtester. As you can see, VectorBT also shows some relevant metrics and charts.

fast_ma = vbt.MA.run(price, 12)
slow_ma = vbt.MA.run(price, 24)
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=10_000,freq='1D')
pf.stats()
pf.plot()
Metrics calculated using VectorBT
Trades generated using VectorBT
Plots generated with VectorBT

Differences between Backtesting.py and VectorBT

You might have noticed that although we used the same strategy and data for running both backtests, the results of the frameworks are not identical. This is due to the different assumptions that the frameworks used by default.

Indeed, these differences are a perfect example to show the importance of knowing how a backtesting framework works!

Fractional vs. Non-Fractional Orders

If you look at the trade logs of both frameworks, you might notice that Backtesting.py has non-fractional orders and VectorBT has fractional ones. This is mainly because VectorBT was developed primarily with cryptocurrencies in mind, and Backtesting.py was first released when no stock brokers allowed for fractional trading.

Both frameworks lack the ability to switch their respective assumption, which is quite inconvenient. Having said that, you can simulate fractional trading with Backtesting.py by dividing the prices by 100 or 1.000. It might not be an elegant solution, but it is a nice workaround I’ve found.

Order Fill Price

Although both frameworks generate the buy and sell signals simultaneously, they have different assumptions regarding the moment they get filled.

By default, VectorBT fills the order at the close price and Backtesting.py at the opening of the next bar. The latter is the correct approach, and the fact that VectorBT behaves like this by default could almost be considered a bug.

If you want Backtesting.py to replicate the behavior of VectorBT, you can set trade_on_close to False when running the backtest.

Tags:

[convertkit form=4793161]

4 Responses

    • Oleksandr, thanks for letting me know about that project. It looks interesting, but I only want to cover mature libraries. Cipher looks very nice, but due to its lack of users, it probably has quite a few bugs that need to be ironed out first.

Leave a Reply to Martin Mayer-Krebs Cancel reply

Your email address will not be published. Required fields are marked *

[convertkit form=5379902]