Features

Technical indicators

Run TA-Lib, pandas-ta, ta, SMC, WorldQuant Alphas, and native indicators at scale

Which technical indicators can you use, and can you run them over many symbols and parameters at once? VBT runs indicators from TA-Lib, pandas-ta, ta, Technical, Smart Money Concepts, and the WorldQuant 101 Alphas, plus its own compiled indicators, through one interface in Python. Every indicator accepts lists of parameters and returns labeled columns.

Compute RSI with 10 window lengths on 5 ETFs in one call
symbols = ["SPY", "QQQ", "IWM", "TLT", "GLD"]
data = vbt.YFData.pull(symbols, start="2024-01-01", end="2025-01-01")
rsi = vbt.talib("RSI").run(data.close, timeperiod=np.arange(5, 55, 5))  
rsi.real.shape
(252, 50)
rsi.real.columns[:3]
MultiIndex([(5, 'SPY'),
            (5, 'QQQ'),
            (5, 'IWM')],
           names=['rsi_timeperiod', 'symbol'])
rsi.real.iloc[-1].unstack("symbol").round(1).head(4)  
symbol           GLD   IWM   QQQ   SPY   TLT
rsi_timeperiod
5               51.2  32.5  29.0  29.5  32.7
10              47.6  33.9  40.7  37.8  33.1
15              47.4  37.7  45.7  42.4  35.7
20              47.9  40.9  48.4  45.5  37.5

Indicator libraries

Indicators from each library are available by name with a prefix: vbt.talib("RSI"), vbt.pandas_ta("SUPERTREND"), vbt.ta("RSIIndicator"), and vbt.indicator("smc:...") for Smart Money Concepts or "wqa101:..." for the WorldQuant 101 Alphas. Each one is wrapped in the same indicator class as VBT's own, so it accepts parameter lists, labels its outputs, offers signal helpers such as crossed_above, and plots. The libraries themselves are optional dependencies, and VBT only uses the ones you install. vbt.IF.list_indicators("*vwap*") searches all of them by name and returns, for example, ['vbt:VWAP', 'pandas_ta:VWAP'] when pandas-ta is installed. TA-Lib also brings candlestick patterns and studies such as Parabolic SAR, listed in its function catalogue. Many WorldQuant alphas rank values across assets, so they need several symbols in one call: with a single asset, every cross-sectional rank is the same. Some formulas also use sector or industry groups, making them useful for research across a classified universe.

Running an indicator returns an indicator object, not a DataFrame. Its outputs are attributes named after them, such as .rsi for vbt.RSI and .real for most TA-Lib indicators, and output_names lists them. The highlights below show Smart Money Concepts, the WorldQuant Alphas, and the Technical library from Freqtrade.

Built-in indicators

VBT ships compiled indicators of its own: moving averages (vbt.MA), standard deviation (vbt.MSD), Bollinger Bands (vbt.BBANDS), RSI (vbt.RSI), stochastic (vbt.STOCH), MACD (vbt.MACD), ATR (vbt.ATR), ADX (vbt.ADX), on-balance volume (vbt.OBV), VWAP (vbt.VWAP), SuperTrend (vbt.SUPERTREND), and pivot detection with a ZigZag line (vbt.PIVOTINFO). VWAP resets every day by default, and its anchor parameter sets another period. They run in Numba without any extra dependency. When speed matters more than the indicator class, vbt.talib_func calls a TA-Lib function directly with broadcasting, missing-value handling, and timeframes, as the Lightweight TA-Lib highlight shows.

Moving averages offer simple, weighted, exponential, Wilder, and VIDYA smoothing through wtype. Bollinger Bands also expose bandwidth and percent B, so you can study volatility contractions or where a price sits within its bands. SuperTrend returns trend direction alongside its lines, which you can use as a filter for another indicator's entries.

Compare parameters and generate signals

Parameter lists let you compare settings without writing a loop for each one. With several parameters, lists are paired by default. Set param_product=True to test every combination. The outputs keep the parameter and symbol labels, and crossing helpers produce Boolean signals with the same columns.

Here are two fictional price series, two lookback windows, and two band widths. The result is eight columns of Bollinger Bands and a count of upper-band breakouts for each setting:

Compare Bollinger Band breakout settings
close = pd.DataFrame({
    "A": [10, 11, 10, 10, 14, 11, 10, 15, 12, 11, 16, 12],
    "B": [20, 19, 20, 20, 16, 19, 20, 15, 18, 19, 14, 18],
}, index=pd.date_range("2025-01-01", periods=12))
close.columns.name = "symbol"
bands = vbt.BBANDS.run(close, window=[3, 5], alpha=[1.0, 1.5], param_product=True)
entries = bands.close_crossed_above(bands.upper)
bands.upper.shape
(12, 8)
entries.sum().unstack("symbol")
symbol              A  B
bb_window bb_alpha
3         1.0       3  0
          1.5       0  0
5         1.0       2  0
          1.5       0  0

The wider bands produce fewer breakouts on these prices. Use the signals as entry conditions, combine them with a trend or volume filter, and add exit rules in Signal backtesting. For larger searches and comparing strategy results across settings, see Parameter optimization.

Statistical indicators

vbt.HURST estimates the Hurst exponent to tell trending from mean-reverting behavior, and vbt.OLS fits a rolling regression of one series on another, which is the base of many pairs trading strategies. vbt.PATSIM measures similarity to a pattern, as described on the Patterns and event studies page. The Hurst exponent and Rolling OLS highlights below show the first two. If your research calls for another statistic, the indicator factory lets you wrap your own Python or Numba calculation with the same parameter and output interface.

Alternative charts

Renko bricks turn a price series into fixed-size moves and ignore time, which filters noise. The Renko chart highlight below builds them from closes and resamples them to OHLC bars. For a custom candle transform such as Heikin-Ashi, you can also wrap the calculation with the indicator factory and retain separate open, high, low, and close outputs.

Running indicators

Indicators run on one or many columns, and data.run("rsi") picks the right inputs from a data object. TA-Lib indicators take skipna=True to skip missing values, so an asset that started trading later does not leave the rest of its column empty.

Different libraries can disagree on the first values of the same indicator, because they start their smoothing in different ways. In this RSI comparison, the values converge after a warm-up period:

Compare TA-Lib's RSI with VBT's RSI
btc = vbt.YFData.pull("BTC-USD", start="2024-01-01", end="2025-01-01")
talib_rsi = vbt.talib("RSI").run(btc.close, timeperiod=14).real
vbt_rsi = vbt.RSI.run(btc.close, window=14).rsi
pd.DataFrame({"talib": talib_rsi, "vbt": vbt_rsi}).iloc[[14, 15, 100, -1]].round(2)
                           talib    vbt
Date
2024-01-15 00:00:00+00:00  44.24  58.19
2024-01-16 00:00:00+00:00  46.80  60.27
2024-04-10 00:00:00+00:00  56.07  56.08
2024-12-31 00:00:00+00:00  43.51  43.51

When matching another platform's values matters, load more history than you analyze so the warm-up is over before your period starts. Match the input prices, timeframe, and smoothing settings too.

If you only need arrays for further calculations, return_raw="outputs" returns NumPy outputs without constructing the final indicator object and labeled output columns. For indicators on a different calculation timeframe, see Multi-timeframe analysis. For updating calculations as new bars arrive, see Streaming indicators.

Hurst exponent

✅ Estimating the Hurst exponent provides insight into persistence and mean-reverting behavior in your data. VBT offers five (!) different implementations.

Plot rolling Hurst exponent by method
data = vbt.YFData.pull("BTC-USD", start="12 months ago")
hurst = vbt.HURST.run(data.close, method=["standard", "logrs", "rs", "dma", "dsod"])
fig = vbt.make_subplots(specs=[[dict(secondary_y=True)]])
data.plot(plot_volume=False, ohlc_trace_kwargs=dict(opacity=0.3), fig=fig)
fig = hurst.hurst.vbt.plot(fig=fig, add_trace_kwargs=dict(secondary_y=True))
fig = fig.select_range(start=hurst.param_defaults["window"])
fig.show()
Rolling Hurst exponent by method over BTC-USD market data Figure data (JSON)

Smart Money Concepts

✅ VBT integrates most of the indicators from the Smart Money Concepts (SMC) library.

Plot previous high and low
data = vbt.YFData.pull("BTC-USD", start="6 months ago")
phl = vbt.smc("previous_high_low").run(  
    data.open,
    data.high,
    data.low,
    data.close,
    data.volume,
    time_frame=vbt.Default("7D")
)
fig = data.plot()
phl.previous_high.rename("previous_high").vbt.plot(fig=fig)
phl.previous_low.rename("previous_low").vbt.plot(fig=fig)
(phl.broken_high == 1).rename("broken_high").vbt.signals.plot_as_markers(
    y=phl.previous_high,
    trace_kwargs=dict(marker=dict(color="limegreen")),
    fig=fig
)
(phl.broken_low == 1).rename("broken_low").vbt.signals.plot_as_markers(
    y=phl.previous_low,
    trace_kwargs=dict(marker=dict(color="orangered")),
    fig=fig
)
fig.show()
BTC-USD OHLCV with previous weekly highs and lows and broken-level markers Figure data (JSON)

Lightweight TA-Lib

✅ TA-Lib functions wrapped with the indicator factory are very powerful because, unlike the official TA-Lib implementation, they can broadcast, handle DataFrames, skip missing values, and even resample to a different timeframe. Although TA-Lib functions are very fast, wrapping them with the indicator factory adds some overhead. To keep both the speed of TA-Lib and the power of VBT, the added features have been separated into a lightweight function that you can call just like a regular TA-Lib function.

Run and plot an RSI resampled to the monthly timeframe
data = vbt.YFData.pull("BTC-USD")
run_rsi = vbt.talib_func("rsi")
rsi = run_rsi(data.close, timeperiod=12, timeframe="M")  
rsi
Date
2014-09-17 00:00:00+00:00          NaN
2014-09-18 00:00:00+00:00          NaN
2014-09-19 00:00:00+00:00          NaN
2014-09-20 00:00:00+00:00          NaN
2014-09-21 00:00:00+00:00          NaN
                                   ...
2024-01-18 00:00:00+00:00    64.210811
2024-01-19 00:00:00+00:00    64.210811
2024-01-20 00:00:00+00:00    64.210811
2024-01-21 00:00:00+00:00    64.210811
2024-01-22 00:00:00+00:00    64.210811
Freq: D, Name: Close, Length: 3415, dtype: float64
plot_rsi = vbt.talib_plot_func("rsi")
plot_rsi(rsi).show()
BTC-USD RSI resampled to the monthly timeframe Figure data (JSON)

✅ VBT integrates most of the indicators and consensus classes from freqtrade's technical library.

Compute and plot the summary consensus with a one-liner
vbt.YFData.pull("BTC-USD").run("sumcon", smooth=100).plot().show()
Smoothed technical indicator buy and sell summary consensus for BTC-USD Figure data (JSON)

Renko chart

✅ Unlike regular charts, a Renko chart is built using price movements. Each "brick" appears when the price changes by a specified amount. Because the output has irregular time intervals, only one column can be processed at once. As with everything, VBT's implementation can translate a huge number of data points very fast thanks to Numba.

Resample closing price into a Renko format
data = vbt.YFData.pull("BTC-USD", start="2021", end="2022")
renko_ohlc = data.close.vbt.to_renko_ohlc(1000, reset_index=True)  
renko_ohlc.vbt.ohlcv.plot().show()
BTC-USD closing price resampled into a Renko OHLC chart Figure data (JSON)

Rolling OLS

✅ Rolling regressions are models for analyzing changing relationships among variables over time. In VBT, this is implemented as an indicator that takes two time series and returns the slope, intercept, prediction, error, R-squared, and the z-score of the error at each time step. Use the regression and residuals in pairs research, for example to build a spread and test entry or rebalancing rules. It is also hundreds of times faster than the statsmodels equivalent RollingOLS 🔥

Determine the spread between BTC and ETH
data = vbt.YFData.pull(
    ["BTC-USD", "ETH-USD"],
    start="2022",
    end="2023",
    missing_index="drop"
)
ols = vbt.OLS.run(
    data.get("Close", "BTC-USD"),
    data.get("Close", "ETH-USD")
)
ols.plot_zscore().show()
Rolling OLS spread z-score between BTC and ETH during 2022 Figure data (JSON)

TA-Lib plotting

✅ Every TA-Lib indicator is fully capable of plotting itself, based entirely on output flags!

data = vbt.YFData.pull("BTC-USD", start="2020", end="2021")

vbt.talib("MACD").run(data.close).plot().show()
TA-Lib MACD, signal, and histogram for BTC-USD during 2020 Figure data (JSON)

✅ Each of WorldQuant's 101 Formulaic Alphas is now available as an indicator 👀

Run the first alpha
data = vbt.YFData.pull(["BTC-USD", "ETH-USD", "XRP-USD"], missing_index="drop")

vbt.wqa101(1).run(data.close).out
symbol                      BTC-USD   ETH-USD   XRP-USD
Date
2017-11-09 00:00:00+00:00  0.166667  0.166667  0.166667
2017-11-10 00:00:00+00:00  0.166667  0.166667  0.166667
2017-11-11 00:00:00+00:00  0.166667  0.166667  0.166667
2017-11-12 00:00:00+00:00  0.166667  0.166667  0.166667
2017-11-13 00:00:00+00:00  0.166667  0.166667  0.166667
...                             ...       ...       ...
2023-01-31 00:00:00+00:00  0.166667  0.166667  0.166667
2023-02-01 00:00:00+00:00  0.000000  0.000000  0.500000
2023-02-02 00:00:00+00:00  0.000000  0.000000  0.500000
2023-02-03 00:00:00+00:00  0.000000  0.500000  0.000000
2023-02-04 00:00:00+00:00 -0.166667  0.333333  0.333333

[1914 rows x 3 columns]

Copyright © 2021–2026 Oleg Polakow. All rights reserved.

Site content and documentation are provided for using and evaluating VectorBT PRO and for educational purposes. Any other use, including building or supporting competing products or services, requires prior written consent.