lucit_backtesting package

Submodules

backtesting.backtesting module

Core framework data structures. Objects from this module can also be imported from the top-level module directly, e.g.

from backtesting import Backtest, Strategy

class backtesting.backtesting.Backtest(data: DataFrame, strategy: Type[Strategy], *, cash: float = 10000, commission: float = 0.0, margin: float = 1.0, trade_on_close=False, hedging=False, exclusive_orders=False)[source]

Bases: object

Backtest a particular (parameterized) strategy on particular data.

Upon initialization, call method backtesting.backtesting.Backtest.run to run a backtest instance, or backtesting.backtesting.Backtest.optimize to optimize it.

optimize(*, maximize: str | Callable[[Series], float] = 'SQN', method: str = 'grid', max_tries: int | float | None = None, constraint: Callable[[dict], bool] | None = None, return_heatmap: bool = False, return_optimization: bool = False, random_state: int | None = None, **kwargs) Series | Tuple[Series, Series] | Tuple[Series, Series, dict][source]

Optimize strategy parameters to an optimal combination. Returns result pd.Series of the best run.

maximize is a string key from the backtesting.backtesting.Backtest.run-returned results series, or a function that accepts this series object and returns a number; the higher the better. By default, the method maximizes Van Tharp’s `System Quality Number<https://google.com/search?q=System+Quality+Number>`__.

method is the optimization method. Currently two methods are supported:

max_tries is the maximal number of strategy runs to perform. If method=”grid”, this results in randomized grid search. If max_tries is a floating value between (0, 1], this sets the number of runs to approximately that fraction of full grid space. Alternatively, if integer, it denotes the absolute maximum number of evaluations. If unspecified (default), grid search is exhaustive, whereas for method=”skopt”, max_tries is set to 200.

constraint is a function that accepts a dict-like object of parameters (with values) and returns True when the combination is admissible to test with. By default, any parameters combination is considered admissible.

If return_heatmap is True, besides returning the result series, an additional pd.Series is returned with a multiindex of all admissible parameter combinations, which can be further inspected or projected onto 2D to plot a heatmap (see backtesting.lib.plot_heatmaps()).

If return_optimization is True and method = ‘skopt’, in addition to result series (and maybe heatmap), return raw [scipy.optimize.OptimizeResult] `OptimizeResult<https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.OptimizeResult.html>`__ for further inspection, e.g. with `scikit-optimize<https://scikit-optimize.github.io>`__ `plotting tools<https://scikit-optimize.github.io/stable/modules/plots.html>`__.

If you want reproducible optimization results, set random_state to a fixed integer random seed.

Additional keyword arguments represent strategy arguments with list-like collections of possible values. For example, the following code finds and returns the “best” of the 7 admissible (of the 9 possible) parameter combinations:

backtest.optimize(sma1=[5, 10, 15], sma2=[10, 20, 40],

constraint=lambda p: p.sma1 < p.sma2)

plot(*, results: Series | None = None, filename=None, plot_width=None, plot_equity=True, plot_return=False, plot_pl=True, plot_volume=True, plot_drawdown=False, plot_trades=True, smooth_equity=False, relative_equity=True, superimpose: bool | str = True, resample=True, reverse_indicators=False, show_legend=True, open_browser=True)[source]

Plot the progression of the last backtest run.

If results is provided, it should be a particular result pd.Series such as returned by backtesting.backtesting.Backtest.run or backtesting.backtesting.Backtest.optimize, otherwise the last run’s results are used.

filename is the path to save the interactive HTML plot to. By default, a strategy/parameter-dependent file is created in the current working directory.

plot_width is the width of the plot in pixels. If None (default), the plot is made to span 100% of browser width. The height is currently non-adjustable.

If plot_equity is True, the resulting plot will contain an equity (initial cash plus assets) graph section. This is the same as plot_return plus initial 100%.

If plot_return is True, the resulting plot will contain a cumulative return graph section. This is the same as plot_equity minus initial 100%.

If plot_pl is True, the resulting plot will contain a profit/loss (P/L) indicator section.

If plot_volume is True, the resulting plot will contain a trade volume section.

If plot_drawdown is True, the resulting plot will contain a separate drawdown graph section.

If plot_trades is True, the stretches between trade entries and trade exits are marked by hash-marked tractor beams.

If smooth_equity is True, the equity graph will be interpolated between fixed points at trade closing times, unaffected by any interim asset volatility.

If relative_equity is True, scale and label equity graph axis with return percent, not absolute cash-equivalent values.

If superimpose is True, superimpose larger-timeframe candlesticks over the original candlestick chart. Default downsampling rule is: monthly for daily data, daily for hourly data, hourly for minute data, and minute for (sub-)second data. superimpose can also be a valid `Pandas offset string<https://pandas.pydata.org/pandas-docs/stable/user_guide/timeseries.html#dateoffset-objects>`__ , such as ‘5T’ or ‘5min’, in which case this frequency will be used to superimpose. Note, this only works for data with a datetime index.

If resample is True, the OHLC data is resampled in a way that makes the upper number of candles for Bokeh to plot limited to 10_000. This may, in situations of overabundant data, improve plot’s interactive performance and avoid browser’s Javascript Error: Maximum call stack size exceeded or similar. Equity & dropdown curves and individual trades data is, likewise, [reasonably _aggregated_] `TRADES_AGG<lib.html#backtesting.lib.TRADES_AGG>`__. resample can also be a `Pandas offset string<https://pandas.pydata.org/pandas-docs/stable/user_guide/timeseries.html#dateoffset-objects>`__ , such as ‘5T’ or ‘5min’, in which case this frequency will be used to resample, overriding above numeric limitation. Note, all this only works for data with a datetime index.

If reverse_indicators is True, the indicators below the OHLC chart are plotted in reverse order of declaration.

If show_legend is True, the resulting plot graphs will contain labeled legends.

If open_browser is True, the resulting filename will be opened in the default web browser.

run(**kwargs) Series[source]

Run the backtest. Returns pd.Series with results and statistics.

Keyword arguments are interpreted as strategy parameters.

>>> Backtest(GOOG, SmaCross).run()
Start                     2004-08-19 00:00:00
End                       2013-03-01 00:00:00
Duration                   3116 days 00:00:00
Exposure Time [%]                     93.9944
Equity Final [$]                      51959.9
Equity Peak [$]                       75787.4
Return [%]                            419.599
Buy & Hold Return [%]                 703.458
Return (Ann.) [%]                      21.328
Volatility (Ann.) [%]                 36.5383
Sharpe Ratio                         0.583718
Sortino Ratio                         1.09239
Calmar Ratio                         0.444518
Max. Drawdown [%]                    -47.9801
Avg. Drawdown [%]                    -5.92585
Max. Drawdown Duration      584 days 00:00:00
Avg. Drawdown Duration       41 days 00:00:00
# Trades                                   65
Win Rate [%]                          46.1538
Best Trade [%]                         53.596
Worst Trade [%]                      -18.3989
Avg. Trade [%]                        2.35371
Max. Trade Duration         183 days 00:00:00
Avg. Trade Duration          46 days 00:00:00
Profit Factor                         2.08802
Expectancy [%]                        8.79171
SQN                                  0.916893
Kelly Criterion                        0.6134
_strategy                            SmaCross
_equity_curve                           Eq...
_trades                       Size  EntryB...
dtype: object

Warning

You may obtain different results for different strategy parameters. E.g. if you use 50- and 200-bar SMA, the trading simulation will begin on bar 201. The actual length of delay is equal to the lookback period of the Strategy.I indicator which lags the most. Obviously, this can affect results.

class backtesting.backtesting.Order(broker: _Broker, size: float, limit_price: float | None = None, stop_price: float | None = None, sl_price: float | None = None, tp_price: float | None = None, parent_trade: Trade | None = None, tag: object | None = None)[source]

Bases: object

Place new orders through Strategy.buy() and Strategy.sell(). Query existing orders through Strategy.orders.

When an order is executed or [filled], it results in a Trade.

If you wish to modify aspects of a placed but not yet filled order, cancel it and place a new one instead.

All placed orders are [Good ‘Til Canceled].

`filled<https://www.investopedia.com/terms/f/fill.asp>`__ `Good 'Til Canceled<https://www.investopedia.com/terms/g/gtc.asp>`__

cancel()[source]

Cancel the order.

property is_contingent

True for `contingent<https://www.investopedia.com/terms/c/contingentorder.asp>`__ orders, i.e. `OCO<https://www.investopedia.com/terms/o/oco.asp>`__ stop-loss and take-profit bracket orders placed upon an active trade. Remaining contingent orders are canceled when their parent Trade is closed.

You can modify contingent orders through Trade.sl and Trade.tp.

property is_long

True if the order is long (order size is positive).

property is_short

True if the order is short (order size is negative).

property limit: float | None

Order limit price for `limit orders<https://www.investopedia.com/terms/l/limitorder.asp>`__, or None for `market orders<https://www.investopedia.com/terms/m/marketorder.asp>`__, which are filled at next available price.

property parent_trade
property size: float

Order size (negative for short orders).

If size is a value between 0 and 1, it is interpreted as a fraction of current available liquidity (cash plus Position.pl minus used margin). A value greater than or equal to 1 indicates an absolute number of units.

property sl: float | None

A stop-loss price at which, if set, a new contingent stop-market order will be placed upon the Trade following this order’s execution. See also Trade.sl.

property stop: float | None

Order stop price for `stop-limit/stop-market order<https://www.investopedia.com/terms/s/stoporder.asp>`__, otherwise None if no stop was set, or the stop price has already been hit.

property tag

Arbitrary value (such as a string) which, if set, enables tracking of this order and the associated Trade (see Trade.tag).

property tp: float | None

A take-profit price at which, if set, a new contingent limit order will be placed upon the Trade following this order’s execution. See also Trade.tp.

class backtesting.backtesting.Position(broker: _Broker)[source]

Bases: object

Currently held asset position, available as backtesting.backtesting.Strategy.position within backtesting.backtesting.Strategy.next. Can be used in boolean contexts, e.g.

if self.position:

… # we have a position, either long or short

close(portion: float = 1.0)[source]

Close portion of position by closing portion of each active trade. See Trade.close.

property is_long: bool

True if the position is long (position size is positive).

property is_short: bool

True if the position is short (position size is negative).

property pl: float

Profit (positive) or loss (negative) of the current position in cash units.

property pl_pct: float

Profit (positive) or loss (negative) of the current position in percent.

property size: float

Position size in units of asset. Negative if position is short.

class backtesting.backtesting.Strategy(broker, data, params)[source]

Bases: object

A trading strategy base class. Extend this class and override methods backtesting.backtesting.Strategy.init and backtesting.backtesting.Strategy.next to define your own strategy.

I(func: Callable, *args, name=None, plot=True, overlay=None, color=None, scatter=False, **kwargs) ndarray[source]

Declare an indicator. An indicator is just an array of values, but one that is revealed gradually in backtesting.backtesting.Strategy.next much like backtesting.backtesting.Strategy.data is. Returns np.ndarray of indicator values.

func is a function that returns the indicator array(s) of same length as backtesting.backtesting.Strategy.data.

In the plot legend, the indicator is labeled with function name, unless name overrides it.

If plot is True, the indicator is plotted on the resulting backtesting.backtesting.Backtest.plot.

If overlay is True, the indicator is plotted overlaying the price candlestick chart (suitable e.g. for moving averages). If False, the indicator is plotted standalone below the candlestick chart. By default, a heuristic is used which decides correctly most of the time.

color can be string hex RGB triplet or X11 color name. By default, the next available color is assigned.

If scatter is True, the plotted indicator marker will be a circle instead of a connected line segment (default).

Additional *args and **kwargs are passed to func and can be used for parameters.

For example, using simple moving average function from TA-Lib:

def init():

self.sma = self.I(ta.SMA, self.data.Close, self.n_sma)

buy(*, size: float = .9999, limit: float | None = None, stop: float | None = None, sl: float | None = None, tp: float | None = None, tag: object | None = None)[source]

Place a new long order. For explanation of parameters, see Order and its properties.

See Position.close() and Trade.close() for closing existing positions.

See also Strategy.sell().

property closed_trades: Tuple[Trade, ...]

List of settled trades (see Trade).

property data: _Data

Price data, roughly as passed into backtesting.backtesting.Backtest.__init__, but with two significant exceptions:

  • data is _not_ a DataFrame, but a custom structure that serves customized numpy arrays for reasons of performance and convenience. Besides OHLCV columns, .index and length, it offers .pip property, the smallest price unit of change.

  • Within backtesting.backtesting.Strategy.init, data arrays are available in full length, as passed into backtesting.backtesting.Backtest.__init__ (for precomputing indicators and such). However, within backtesting.backtesting.Strategy.next, data arrays are only as long as the current iteration, simulating gradual price point revelation. In each call of backtesting.backtesting.Strategy.next (iteratively called by backtesting.backtesting.Backtest internally), the last array value (e.g. data.Close[-1]) is always the most recent value.

  • If you need data arrays (e.g. data.Close) to be indexed Pandas series, you can call their .s accessor (e.g. data.Close.s). If you need the whole of data as a DataFrame, use .df accessor (i.e. data.df).

property equity: float

Current account equity (cash plus assets).

abstract init()[source]

Initialize the strategy. Override this method. Declare indicators (with backtesting.backtesting.Strategy.I). Precompute what needs to be precomputed or can be precomputed in a vectorized fashion before the strategy starts.

If you extend composable strategies from backtesting.lib, make sure to call:

super().init()

abstract next()[source]

Main strategy runtime method, called as each new backtesting.backtesting.Strategy.data instance (row; full candlestick bar) becomes available. This is the main method where strategy decisions upon data precomputed in backtesting.backtesting.Strategy.init take place.

If you extend composable strategies from backtesting.lib, make sure to call:

super().next()

property orders: Tuple[Order, ...]

List of orders (see Order) waiting for execution.

property position: Position

Instance of backtesting.backtesting.Position.

sell(*, size: float = .9999, limit: float | None = None, stop: float | None = None, sl: float | None = None, tp: float | None = None, tag: object | None = None)[source]

Place a new short order. For explanation of parameters, see Order and its properties.

See also Strategy.buy().

Note

If you merely want to close an existing long position, use Position.close() or Trade.close().

property trades: Tuple[Trade, ...]

List of active trades (see Trade).

class backtesting.backtesting.Trade(broker: _Broker, size: int, entry_price: float, entry_bar, tag)[source]

Bases: object

When an Order is filled, it results in an active Trade. Find active trades in Strategy.trades and closed, settled trades in Strategy.closed_trades.

close(portion: float = 1.0)[source]

Place new Order to close portion of the trade at next market price.

property entry_bar: int

Candlestick bar index of when the trade was entered.

property entry_price: float

Trade entry price.

property entry_time: Timestamp | int

Datetime of when the trade was entered.

property exit_bar: int | None

Candlestick bar index of when the trade was exited (or None if the trade is still active).

property exit_price: float | None

Trade exit price (or None if the trade is still active).

property exit_time: Timestamp | int | None

Datetime of when the trade was exited.

property is_long

True if the trade is long (trade size is positive).

property is_short

True if the trade is short (trade size is negative).

property pl

Trade profit (positive) or loss (negative) in cash units.

property pl_pct

Trade profit (positive) or loss (negative) in percent.

property size

Trade size (volume; negative for short trades).

property sl

Stop-loss price at which to close the trade.

This variable is writable. By assigning it a new price value, you create or modify the existing SL order. By assigning it None, you cancel it.

property tag

A tag value inherited from the Order that opened this trade.

This can be used to track trades and apply conditional logic / subgroup analysis.

See also Order.tag.

property tp

Take-profit price at which to close the trade.

This property is writable. By assigning it a new price value, you create or modify the existing TP order. By assigning it None, you cancel it.

property value

Trade total value in cash (volume × price).

backtesting.lib module

Collection of common building blocks, helper auxiliary functions and composable strategy classes for reuse.

Intended for simple missing-link procedures, not reinventing of better-suited, state-of-the-art, fast libraries, such as TA-Lib, Tulipy, PyAlgoTrade, NumPy, SciPy …

Please raise ideas for additions to this collection on the `issue tracker<https://github.com/kernc/backtesting.py>`__.

backtesting.lib.OHLCV_AGG = {'Close': 'last', 'High': 'max', 'Low': 'min', 'Open': 'first', 'Volume': 'sum'}

Dictionary of rules for aggregating resampled OHLCV data frames, e.g.

df.resample(‘4H’, label=’right’).agg(OHLCV_AGG).dropna()

class backtesting.lib.SignalStrategy(broker, data, params)[source]

Bases: Strategy

A simple helper strategy that operates on position entry/exit signals. This makes the backtest of the strategy simulate a `vectorized backtest<https://www.google.com/search?q=vectorized+backtest>`__. See `tutorials<index.html#tutorials>`__ for usage examples.

To use this helper strategy, subclass it, override its backtesting.backtesting.Strategy.init method, and set the signal vector by calling backtesting.lib.SignalStrategy.set_signal method from within it.

class ExampleStrategy(SignalStrategy):
def init(self):

super().init() self.set_signal(sma1 > sma2, sma1 < sma2)

Remember to call super().init() and super().next() in your overridden methods.

next()[source]

Main strategy runtime method, called as each new backtesting.backtesting.Strategy.data instance (row; full candlestick bar) becomes available. This is the main method where strategy decisions upon data precomputed in backtesting.backtesting.Strategy.init take place.

If you extend composable strategies from backtesting.lib, make sure to call:

super().next()

set_signal(entry_size: Sequence[float], exit_portion: Sequence[float] | None = None, *, plot: bool = True)[source]

Set entry/exit signal vectors (arrays).

A long entry signal is considered present wherever entry_size is greater than zero, and a short signal wherever entry_size is less than zero, following backtesting.backtesting.Order.size semantics.

If exit_portion is provided, a nonzero value closes portion the position (see backtesting.backtesting.Trade.close()) in the respective direction (positive values close long trades, negative short).

If plot is True, the signal entry/exit indicators are plotted when backtesting.backtesting.Backtest.plot is called.

backtesting.lib.TRADES_AGG = {'Duration': 'sum', 'EntryBar': 'first', 'EntryPrice': 'mean', 'EntryTime': 'first', 'ExitBar': 'last', 'ExitPrice': 'mean', 'ExitTime': 'last', 'PnL': 'sum', 'ReturnPct': 'mean', 'Size': 'sum'}

Dictionary of rules for aggregating resampled trades data, e.g.

stats[‘_trades’].resample(‘1D’, on=’ExitTime’,

label=’right’).agg(TRADES_AGG)

class backtesting.lib.TrailingStrategy(broker, data, params)[source]

Bases: Strategy

A strategy with automatic trailing stop-loss, trailing the current price at distance of some multiple of average true range (ATR). Call TrailingStrategy.set_trailing_sl() to set said multiple (6 by default). See `tutorials<index.html#tutorials>`__ for usage examples.

Remember to call super().init() and super().next() in your overridden methods.

init()[source]

Initialize the strategy. Override this method. Declare indicators (with backtesting.backtesting.Strategy.I). Precompute what needs to be precomputed or can be precomputed in a vectorized fashion before the strategy starts.

If you extend composable strategies from backtesting.lib, make sure to call:

super().init()

next()[source]

Main strategy runtime method, called as each new backtesting.backtesting.Strategy.data instance (row; full candlestick bar) becomes available. This is the main method where strategy decisions upon data precomputed in backtesting.backtesting.Strategy.init take place.

If you extend composable strategies from backtesting.lib, make sure to call:

super().next()

set_atr_periods(periods: int = 100)[source]

Set the lookback period for computing ATR. The default value of 100 ensures a _stable_ ATR.

set_trailing_sl(n_atr: float = 6)[source]

Sets the future trailing stop-loss as some multiple (n_atr) average true bar ranges away from the current price.

backtesting.lib.barssince(condition: Sequence[bool], default=inf) int[source]

Return the number of bars since condition sequence was last True, or if never, return default.

>>> barssince(self.data.Close > self.data.Open)
3
backtesting.lib.compute_stats(*, stats: Series, data: DataFrame, trades: DataFrame | None = None, risk_free_rate: float = 0.0) Series[source]

(Re-)compute strategy performance metrics.

stats is the statistics series as returned by backtesting.backtesting.Backtest.run(). data is OHLC data as passed to the backtesting.backtesting.Backtest the stats were obtained in. trades can be a dataframe subset of stats._trades (e.g. only long trades). You can also tune risk_free_rate, used in calculation of Sharpe and Sortino ratios.

>>> stats = Backtest(GOOG, MyStrategy).run()
>>> only_long_trades = stats._trades[stats._trades.Size > 0]
>>> long_stats = compute_stats(stats=stats, trades=only_long_trades,
...                            data=GOOG, risk_free_rate=.02)
backtesting.lib.cross(series1: Sequence, series2: Sequence) bool[source]

Return True if series1 and series2 just crossed (above or below) each other.

>>> cross(self.data.Close, self.sma)
True
backtesting.lib.crossover(series1: Sequence, series2: Sequence) bool[source]

Return True if series1 just crossed over (above) series2.

>>> crossover(self.data.Close, self.sma)
True
backtesting.lib.plot_heatmaps(heatmap: Series, agg: str | Callable = 'max', *, ncols: int = 3, plot_width: int = 1200, filename: str = '', open_browser: bool = True)[source]

Plots a grid of heatmaps, one for every pair of parameters in heatmap.

heatmap is a Series as returned by backtesting.backtesting.Backtest.optimize when its parameter return_heatmap=True.

When projecting the n-dimensional heatmap onto 2D, the values are aggregated by ‘max’ function by default. This can be tweaked with agg parameter, which accepts any argument pandas knows how to aggregate by.

`plot_objective<https://scikit-optimize.github.io/stable/modules/plots.html#plot-objective>`__

backtesting.lib.quantile(series: Sequence, quantile: float | None = None)[source]

If quantile is None, return the quantile _rank_ of the last value of series wrt former series values.

If quantile is a value between 0 and 1, return the _value_ of series at this quantile. If used to working with percentiles, just divide your percentile amount with 100 to obtain quantiles.

>>> quantile(self.data.Close[-20:], .1)
162.130
>>> quantile(self.data.Close)
0.13
backtesting.lib.random_ohlc_data(example_data: DataFrame, *, frac=1.0, random_state: int | None = None) DataFrame[source]

OHLC data generator. The generated OHLC data has basic [descriptive statistics](https://en.wikipedia.org/wiki/Descriptive_statistics) similar to the provided example_data.

frac is a fraction of data to sample (with replacement). Values greater than 1 result in oversampling.

Such random data can be effectively used for stress testing trading strategy robustness, Monte Carlo simulations, significance testing, etc.

>>> from backtesting.test import EURUSD
>>> ohlc_generator = random_ohlc_data(EURUSD)
>>> next(ohlc_generator)  # returns new random data
...
>>> next(ohlc_generator)  # returns new random data
...
backtesting.lib.resample_apply(rule: str, func: Callable[[...], Sequence] | None, series: Series | DataFrame | _Array, *args, agg: str | dict | None = None, **kwargs)[source]

Apply func (such as an indicator) to series, resampled to a time frame specified by rule. When called from inside backtesting.backtesting.Strategy.init, the result (returned) series will be automatically wrapped in backtesting.backtesting.Strategy.I wrapper method.

rule is a valid `Pandas offset string<http://pandas.pydata.org/pandas-docs/stable/timeseries.html#offset-aliases>`__ indicating a time frame to resample series to.

func is the indicator function to apply on the resampled series.

series is a data series (or array), such as any of the backtesting.backtesting.Strategy.data series. Due to pandas resampling limitations, this only works when input series has a datetime index.

agg is the aggregation function to use on resampled groups of data. Valid values are anything accepted by pandas/resample/.agg(). Default value for dataframe input is OHLCV_AGG dictionary. Default value for series input is the appropriate entry from OHLCV_AGG if series has a matching name, or otherwise the value “last”, which is suitable for closing prices, but you might prefer another (e.g. “max” for peaks, or similar).

Finally, any *args and **kwargs that are not already eaten by implicit backtesting.backtesting.Strategy.I call are passed to func.

For example, if we have a typical moving average function SMA(values, lookback_period), _hourly_ data source, and need to apply the moving average MA(10) on a _daily_ time frame, but don’t want to plot the resulting indicator, we can do:

class System(Strategy):
    def init(self):
        self.sma = resample_apply(
            'D', SMA, self.data.Close, 10, plot=False)

The above short snippet is roughly equivalent to:

class System(Strategy):
    def init(self):
        # Strategy exposes `self.data` as raw NumPy arrays.
        # Let's convert closing prices back to pandas Series.
        close = self.data.Close.s

        # Resample to daily resolution. Aggregate groups
        # using their last value (i.e. closing price at the end
        # of the day). Notice `label='right'`. If it were set to
        # 'left' (default), the strategy would exhibit
        # look-ahead bias.
        daily = close.resample('D', label='right').agg('last')

        # We apply SMA(10) to daily close prices,
        # then reindex it back to original hourly index,
        # forward-filling the missing values in each day.
        # We make a separate function that returns the final
        # indicator array.
        def SMA(series, n):
            from backtesting.test import SMA
            return SMA(series, n).reindex(close.index).ffill()

        # The result equivalent to the short example above:
        self.sma = self.I(SMA, daily, 10, plot=False)

Module contents

![xkcd.com/1570](https://imgs.xkcd.com/comics/engineer_syllogism.png)

## Manuals

  • [Quick Start User Guide](../examples/Quick Start User Guide.html)

## Tutorials

  • [Library of Utilities and Composable Base Strategies](../examples/Strategies Library.html)

  • [Multiple Time Frames](../examples/Multiple Time Frames.html)

  • [Parameter Heatmap & Optimization](../examples/Parameter Heatmap &amp; Optimization.html)

  • [Trading with Machine Learning](../examples/Trading with Machine Learning.html)

These tutorials are also available as live Jupyter notebooks: [![Binder](https://mybinder.org/badge_logo.svg)][binder] [![Google Colab](https://colab.research.google.com/assets/colab-badge.png)][colab] <br>In Colab, you might have to !pip install backtesting.

[binder]: https://mybinder.org/v2/gh/kernc/backtesting.py/master?urlpath=lab%2Ftree%2Fdoc%2Fexamples%2FQuick%20Start%20User%20Guide.ipynb [colab]: https://colab.research.google.com/github/kernc/backtesting.py/

## Example Strategies

  • (contributions welcome)

Tip

For an overview of recent changes, see [What’s New](https://github.com/kernc/backtesting.py/blob/master/CHANGELOG.md).

## FAQ

Some answers to frequent and popular questions can be found on the [issue tracker](https://github.com/kernc/backtesting.py/issues?q=label%3Aquestion+-label%3Ainvalid) or on the [discussion forum](https://github.com/kernc/backtesting.py/discussions) on GitHub. Please use the search!

## License

This software is licensed under the terms of [AGPL 3.0]{: rel=license}, meaning you can use it for any reasonable purpose and remain in complete ownership of all the excellent trading strategies you produce, but you are also encouraged to make sure any upgrades to _Backtesting.py_ itself find their way back to the community.

[AGPL 3.0]: https://www.gnu.org/licenses/agpl-3.0.html

# API Reference Documentation