Library / SDK
kernc/backtesting.py avatar
kernc/backtesting.py

backtesting.py: A Single-File Strategy Backtester for Python Traders

🔎 📈 🐍 💰 Backtest trading strategies in Python.

9,010 stars1,543 forksPythonAGPL-3.0

At a glance

What is it?
backtesting.py wraps a pandas DataFrame and a Strategy subclass into a fast OHLC backtest with a Bokeh chart and a built-in optimizer. It is for Python developers who want to test a rule-based idea in an afternoon, not for teams running live multi-asset portfolios.
Who is it for?
Adopt backtesting.py if you write Python, your data is a single OHLC(V) series, and you want trade-level output plus an interactive chart without wiring up a data feed. Skip it if you need tick data, partial fills, multi-asset portfolio accounting or live execution; the README describes none of those.
Can I use it commercially?
Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
Is it still maintained?
Yes. The repository last received commits 56 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What backtesting.py actually solves for a solo Python developer

The gap it fills is narrow and real. You have a pandas DataFrame of OHLC(V) candles and a rule you believe in. Turning that into an equity curve normally means writing your own position tracker, commission model and trade log, then debugging them before you can trust a single number. backtesting.py supplies that layer. You subclass Strategy, compute indicators in init, place orders in next, and the library returns a pandas Series of statistics plus a DataFrame of individual trades. The README's own example prints 93 trades, a 53.76 percent win rate and a -33.08 percent max drawdown for a 10/20 SMA crossover on GOOG, which is the level of detail the framework is built to produce.

The audience is the person who already knows Python and pandas. The README advertises an indicator-library-agnostic design, so you bring your own indicator code rather than learning a domain-specific expression language. It supports any instrument that has OHLC(V) candlestick data, which is why the topics list forex, stocks and crypto-adjacent use cases together. What it is not is a portfolio engine. There is no mention of multi-symbol allocation, order book simulation or live brokerage connection in the README, and that silence is the boundary of the tool.

The Strategy lifecycle and where your code runs

The mechanism is a vectorized data container plus an event loop over bars. Backtest takes the price data, your Strategy class, and parameters such as commission and exclusive_orders. Inside init, self.I(...) registers an indicator array; the README passes the SMA helper and the Close series to it. Inside next, the framework calls your code once per bar, and self.buy() or self.sell() places an order that the engine fills according to its own rules.

Two design choices matter. First, indicators are computed once up front through self.I, not recomputed each bar, which is where much of the speed comes from. Second, the optimizer is built in and the README attributes it to SAMBO, a separate optimization project. You can sweep parameters without leaving the library. The output objects are deliberately plain: a Series of stats and a DataFrame of trades, so you can post-process them with ordinary pandas rather than a proprietary result object. Visualizations are Bokeh-based and interactive, which is a heavier dependency than a static matplotlib chart but gives you zoom and hover on the equity curve.

Installing backtesting.py and running the SMA crossover

The README gives two install paths: the released package from PyPI, or the master branch from GitHub if you want unreleased changes.

bash
pip install backtesting

For the bleeding edge, the README gives this alternative, which pulls directly from the repository:

bash
pip install git+https://github.com/kernc/backtesting.py

Note the distribution name on PyPI is backtesting, while the import name is backtesting. setup.py exits with an error on Python older than 3.9, so check your interpreter first. The core dependencies are numpy, pandas and bokeh, with minimum versions pinned in setup.py.

The first real use is the README's SmaCross example. It imports a sample dataset, GOOG, from backtesting.test, which means you can run it before you have any data of your own.

python
from backtesting import Backtest, Strategy
from backtesting.lib import crossover
from backtesting.test import SMA, GOOG

class SmaCross(Strategy):
    def init(self):
        price = self.data.Close
        self.ma1 = self.I(SMA, price, 10)
        self.ma2 = self.I(SMA, price, 20)

    def next(self):
        if crossover(self.ma1, self.ma2):
            self.buy()
        elif crossover(self.ma2, self.ma1):
            self.sell()

bt = Backtest(GOOG, SmaCross, commission=.002, exclusive_orders=True)
stats = bt.run()
bt.plot()

Running this prints the statistics table shown in the README, covering the period from 2004-08-19 to 2013-03-01, and bt.plot() opens the interactive chart in a browser. The commission value .002 is the README's own figure; change it to match your broker before you believe any result. Once the sample works, replace GOOG with your own DataFrame that has Open, High, Low, Close and optionally Volume columns.

Where the framework stops being the right tool

The honest limitation is scope. backtesting.py models a single instrument's bar-by-bar simulation. The README never describes order book depth, partial fills, margin calls, short borrow costs or multi-asset portfolio accounting. If your strategy depends on any of those, the statistics it prints will be optimistic in ways the library cannot tell you about. A strategy that looks profitable under the default fill assumptions can be untradeable once slippage and liquidity enter.

There is also a data-quality dependency. The framework accepts whatever OHLC(V) frame you hand it. It does not fetch data, adjust for splits and dividends, or validate that your timestamps are ordered and gap-free. Garbage candles produce a clean-looking equity curve. The sample GOOG data in backtesting.test is a convenience for the tutorial, not a data source for research.

Finally, the optimizer is a search over parameters you define. The README presents it as a feature, and it is, but a parameter sweep over one historical window is a curve-fitting exercise unless you hold out data yourself. Nothing in the library prevents you from optimizing into noise.

backtesting.py vs Backtrader and vectorbt

The README points to a doc/alternatives.md file in the repository for a list of other Python backtesting frameworks, so the maintainers treat comparison as a documented topic rather than a marketing one. The practical difference comes down to architecture.

Backtrader is built around a line-based, event-driven engine with broker, sizer and analyzer abstractions. That structure supports multi-data feeds, live brokerage integrations and resampling, at the cost of more concepts to learn before your first run. backtesting.py collapses that into one Backtest object and one Strategy class. If your idea is one symbol and one timeframe, the smaller surface is an advantage; if you need a portfolio of instruments sharing capital, Backtrader's model is closer to the problem.

vectorbt takes the opposite approach from both: it vectorizes across parameter combinations and symbols, so a sweep of thousands of configurations is expressed as array operations. That scales better for large parameter grids, but it pushes you toward array-shaped thinking and away from the imperative next-bar style that backtesting.py uses. Someone who wants to read their strategy top to bottom like a trading rule will find backtesting.py more legible; someone who wants to evaluate ten thousand variants will not.

Licence, maintenance and the upgrade cost you are taking on

backtesting.py is licensed AGPL-3.0, stated in setup.py and in LICENSE.md. That is a copyleft licence with a network clause. If you modify the library and let users interact with it over a network, the AGPL's obligations extend to that modified version. Using it as an unmodified dependency inside your own strategy code is a different situation from forking the engine and hosting it. This is not legal advice, and the distinction matters enough that you should read LICENSE.md and get your own answer before shipping a hosted product built on a fork.

The repository is not archived, and the last push was on 2026-08-05. That is recent enough that the project is not dormant, but the README does not publish a release cadence or a support commitment. The upgrade cost is tied to the dependency pins: numpy, pandas and bokeh all have minimum versions in setup.py, and bokeh in particular has excluded specific releases (3.0.* and 3.2.*), which tells you the visualization layer is the fragile part of the stack. If you pin bokeh tightly and the project later requires a newer major version, bt.plot() is where your upgrade will hurt. The statistics output is plain pandas, so the analytical core is far less likely to break under you than the charting.

Editorial conclusion

Adopt backtesting.py if you write Python, your data is a single OHLC(V) series, and you want trade-level output plus an interactive chart without wiring up a data feed. Skip it if you need tick data, partial fills, multi-asset portfolio accounting or live execution; the README describes none of those. Before committing, run the README's SmaCross example against your own CSV, check that the backtesting.test module is only a sample dataset, and read LICENSE.md, because AGPL-3.0 governs what you can do with a modified copy served over a network.

Frequently asked questions

How do I install backtesting.py?

The README gives pip install backtesting for the released version, or pip install git+https://github.com/kernc/backtesting.py for the master branch. setup.py requires Python 3.9 or newer and will exit with an error on older interpreters.

How do I use backtesting.py to run a first backtest?

Subclass Strategy, compute indicators in init with self.I, and place orders in next with self.buy or self.sell. Then create Backtest(data, YourStrategy), call run() for the statistics Series and plot() for the interactive Bokeh chart, as the README's SmaCross example does.

Is backtesting.py better than Backtrader?

They target different shapes of problem. backtesting.py is a single-instrument, bar-by-bar engine with one Backtest object and one Strategy class, while Backtrader's line-based engine is built for multiple data feeds and broker abstractions. The repository keeps a doc/alternatives.md file listing other Python backtesting frameworks.

Is backtesting.py free?

It is published on PyPI as the backtesting package and licensed AGPL-3.0, as stated in setup.py and LICENSE.md. The AGPL is a copyleft licence, so the obligations differ between using it as a dependency and distributing or hosting a modified version.

What is backtesting.py?

It is a Python framework for backtesting trading strategies against OHLC(V) candlestick data. The README describes a well-documented API, a built-in optimizer based on SAMBO, detailed trade results as Series and DataFrame objects, and interactive visualizations.

Official sources

  1. Issues
  2. kernc/backtesting.py on GitHub
  3. License: AGPL-3.0
  4. Project website
  5. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/kernc-backtesting-py.svg)](https://hysenlabs.com/projects/kernc-backtesting-py)