Skip to content

Indicators

Question

Learn more in Indicators documentation.

Listing

To list the currently supported indicators, use IndicatorFactory.list_indicators. The returned indicator names can be filtered by location, which can be listed with IndicatorFactory.list_locations, or by evaluating a glob or regex pattern.

List supported indicators and locations
indicator_names = vbt.IF.list_indicators()  # (1)!
indicator_names = vbt.IF.list_indicators("vbt")  # (2)!
indicator_names = vbt.IF.list_indicators("talib")  # (3)!
indicator_names = vbt.IF.list_indicators("RSI*")  # (4)!
indicator_names = vbt.IF.list_indicators("*ma")  # (5)!
indicator_names = vbt.IF.list_indicators("[a-z]+ma$", use_regex=True)  # (6)!
indicator_names = vbt.IF.list_indicators("*ma", location="pandas_ta")  # (7)!

location_names = vbt.IF.list_locations()  # (8)!
  1. List all indicators
  2. List all custom implemented VBT indicators
  3. List all TA-Lib indicators
  4. List any indicators that start with "RSI", such as "RSI" and "RSIIndicator"
  5. List any indicators that end with "ma", such as "MA" and "SMA"
  6. Same as above but as a regular expression
  7. Same as above but only offered by Pandas TA
  8. List all locations

Note

Without specifying a location, indicators across all the locations will be parsed, which may take some time. Thus, make sure to not repeatedly call this function; instead, save the results to a variable.


+

To get the class of an indicator, use IndicatorFactory.get_indicator.

How to get the indicator class
vbt.BBANDS  # (1)!

BBANDS = vbt.IF.get_indicator("pandas_ta:BBANDS")  # (2)!
BBANDS = vbt.indicator("pandas_ta:BBANDS")  # (3)!
BBANDS = vbt.IF.from_pandas_ta("BBANDS")  # (4)!
BBANDS = vbt.pandas_ta("BBANDS")  # (5)!

RSI = vbt.indicator("RSI")  # (6)!
  1. Custom implemented VBT indicators can be accessed directly
  2. Get the indicator class by name as returned by list_indicators
  3. Same as above
  4. Same as above by calling the respective function
  5. Same as above
  6. Search for an indicator with the name "RSI" and return the first found. Custom, TA-LIB, and Pandas-TA indicators are preferred, in this order.

+

To get familiar with an indicator class, call phelp on the run class method, which is used to run the indicator. Alternatively, the specification such as input names is also available via various properties to be accessed in a programmable fashion.

How to get the specification of an indicator class
vbt.phelp(vbt.OLS.run)  # (1)!

print(vbt.OLS.input_names)  # (2)!
print(vbt.OLS.param_names)  # (3)!
print(vbt.OLS.param_defaults)  # (4)!
print(vbt.OLS.in_output_names)  # (5)!
print(vbt.OLS.output_names)  # (6)!
print(vbt.OLS.lazy_output_names)  # (7)!
  1. Get the signature of the run class method along with the specification
  2. Get the input names, such as "close" in talib:SMA. These are the arrays based on which the indicator is computed.
  3. Get the parameter names, such as "timeperiod" in talib:SMA. These are the parameters that are being tested.
  4. Get the parameter defaults
  5. Get the in-output names, such as "stop_ts" in vbt:STX. These are the arrays that are written in-place by the indicator.
  6. Get the output names, such as "entries" and "exits" in vbt:RANDNX. These are the arrays that are returned by the indicator.
  7. Get the lazy output names, such as "bandwidth" in vbt:BBANDS. These are the arrays that can be optionally calculated after the indicator has finished computing.

Running

To run an indicator, call the IndicatorBase.run class method of its class by manually passing the input arrays (which can be any array-like objects such as Pandas DataFrames and NumPy arrays), parameters (which can be single values and lists for testing multiple parameter combinations), and other arguments expected by the indicator. The result of running the indicator is an indicator instance (not the actual arrays!).

How to run an indicator
bbands = vbt.BBANDS.run(close)  # (1)!
bbands = vbt.BBANDS.run(open)  # (2)!
bbands = vbt.BBANDS.run(close, window=20)  # (3)!
bbands = vbt.BBANDS.run(close, window=vbt.Default(20))  # (4)!
bbands = vbt.BBANDS.run(close, window=20, hide_params=["window"])  # (5)!
bbands = vbt.BBANDS.run(close, window=20, hide_params=True)  # (6)!
bbands = vbt.BBANDS.run(close, window=[10, 20, 30])  # (7)!
bbands = vbt.BBANDS.run(close, window=[10, 20, 30], alpha=[2, 3, 4])  # (8)!
bbands = vbt.BBANDS.run(close, window=[10, 20, 30], alpha=[2, 3, 4], param_product=True)  # (9)!
  1. Run the indicator on close price and with default parameters
  2. Run the indicator on open price. You can pass any time series if the indicator expects only "close". But as soon as it expects other time series such as "open", "high", or "low", use only "close".
  3. Test a window of 20. If the close price is a DataFrame, this will append a new column level called "window". If the close price is a Series, it's name will become a tuple.
  4. To avoid adding a new column level, wrap with Default
  5. Alternatively, hide the parameter
  6. Hide all parameters. Makes only sense when only one parameter combination is being tested, and you want the output arrays to have the same columns/name as the input arrays.
  7. Test three windows. This will produce three Series/DataFrames stacked into one DataFrame along columns.
  8. Test three parameter combinations: (10, 2), (20, 3) and (30, 4)
  9. Test all combinations between both parameters, leading to overall 9 tests

Warning

Testing a wide grid of parameter combinations will produce wide arrays. For example, testing 10000 parameter combinations on one year of daily data would produce an array that takes 30MB of RAM. If the indicator returns three arrays, the RAM consumption would be at least 120MB. One year of minute data would result in staggering 40GB. Thus, for testing wide parameter grids it's recommended to test only a subset of combinations at a time, such as with the use of parameterization or chunking.


+

Often, there's a need to make an indicator skip missing values. For this, use skipna=True. This argument not only works for TA-Lib indicators but for any indicators, the only requirement: the jitted loop must be disabled. Also, when a two-dimensional input array is passed, you need to additionally pass split_columns=True to split its columns and process one column at once.

Run an indicator on valid values only
bbands = vbt.BBANDS.run(close_1d, skipna=True)
bbands = vbt.BBANDS.run(close_2d, split_columns=True, skipna=True)

+

Another way is to remove missing values altogether.

Remove missing values in an indicator
bbands = bbands.dropna()  # (1)!
bbands = bbands.dropna(how="all")  # (2)!
  1. Remove any row that has at least one missing value across all outputs
  2. Remove any row that has all values missing across all outputs

+

To retrieve the output arrays from an indicator instance, either access each as an attribute, or use various unpacking options such as IndicatorBase.unpack.

How to retrieve output arrays
bbands = vbt.talib("BBANDS").run(close)
upperband_df = bbands.upperband  # (1)!
middleband_df = bbands.middleband
lowerband_df = bbands.lowerband
upperband_df, middleband_df, lowerband_df = bbands.unpack()  # (2)!
output_dict = bbands.to_dict()  # (3)!
output_df = bbands.to_frame()  # (4)!

sma = vbt.talib("SMA").run(close)
sma_df = sma.real  # (5)!
sma_df = sma.sma  # (6)!
sma_df = sma.output  # (7)!
sma_df = sma.unpack()
  1. Retrieve the upper band array from the indicator instance
  2. Retrieve the output arrays in the same order as they are in bbands.output_names
  3. Retrieve the dictionary with the output arrays
  4. Retrieve a DataFrame with the output arrays stacked along columns
  5. If a TA-Lib indicator has only one output array, it's usually named "real"
  6. The only output can also be accessed by the short name of the indicator
  7. Also, the only output has an alias "output"

+

To keep outputs in the NumPy format and/or omit any shape checks, use return_raw="outputs".

Keep NumPy format
upperband, middleband, lowerband = vbt.talib("BBANDS").run(close, return_raw="outputs")

+

An even simpler way to run indicators is by using Data.run, which takes an indicator name or class, identifies what input names the indicator expects, and then runs the indicator while passing all the inputs found in the data instance automatically. This method also allows unpacking and running multiple indicators, which is very useful for feature engineering.

How to run indicators automatically
bbands = data.run("vbt:BBANDS")  # (1)!
bbands = data.run("vbt:BBANDS", window=20)  # (2)!
upper, middle, lower = data.run("vbt:BBANDS", unpack=True)  # (3)!

features_df = data.run(["talib:BBANDS", "talib:RSI"])  # (4)!
bbands, rsi = data.run(["talib:BBANDS", "talib:RSI"], concat=False)  # (5)!
features_df = data.run(  # (6)!
    ["talib:BBANDS", "talib:RSI"], 
    timeperiod=vbt.run_func_dict(talib_bbands=20, talib_rsi=30),
    hide_params=True
)
features_df = data.run(  # (7)!
    ["talib:BBANDS", "vbt:RSI"], 
    talib_bbands=vbt.run_arg_dict(timeperiod=20),
    vbt_rsi=vbt.run_arg_dict(window=30),
    hide_params=True
)
features_df = data.run("talib_all")  # (8)!
  1. Run vbt.BBANDS with the "close" input name automatically substituted by data.close
  2. Any arguments will be passed down to the indicator's run class method
  3. The output arrays can be directly unpacked. The argument unpack also accepts the options "dict" and "frame".
  4. Run multiple indicators. By default, they will be concatenated into a DataFrame along columns. The function and output names will be visible in the column levels "run_func" and "output" respectively.
  5. Do not concatenate indicators but return them as a list
  6. Pass different values under the same parameter name using run_func_dict
  7. Pass different keyword arguments to each indicator using run_arg_dict
  8. Run all TA-Lib indicators

+

To quickly run and plot a TA-Lib indicator on a single parameter combination without using the indicator factory, use talib_func and talib_plot_func respectively. In contrast to the official TA-Lib implementation, it can properly handle DataFrames, NaNs, broadcasting, and timeframes. The indicator factory's TA-Lib version is based on these two functions.

Quickly run and plot a TA-Lib indicator
run_bbands = vbt.talib_func("BBANDS")
upperband, middleband, lowerband = run_bbands(close, timeperiod=2)
upperband, middleband, lowerband = data.run("talib_func:BBANDS", timeperiod=2)  # (1)!

plot_bbands = vbt.talib_plot_func("BBANDS")
fig = plot_bbands(upperband, middleband, lowerband)
  1. Same as above

Parallelization

Parameter combinations are processed using execute such that it's fairly easy to parallelize their execution.

Various parallelization configurations
any_indicator.run(...)  # (1)!

# ______________________________________________________________

numba_indicator.run(  # (2)!
    ...,
    jitted_loop=True,  # (3)!
    jitted_warmup=True,    # (4)!
    execute_kwargs=dict(n_chunks="auto", engine="threadpool")
)

# ______________________________________________________________

python_indicator.run(  # (5)!
    ...,
    execute_kwargs=dict(n_chunks="auto", distribute="chunks", engine="pathos")
)
  1. By default, the method processes parameter combinations serially (i.e., not in parallel)
  2. If the indicator is compiled with Numba and nogil is enabled, divide parameter combinations into an optimal number of chunks and execute all chunks in parallel with multithreading (i.e., one chunk per thread)
  3. Wrap the loop with Numba that goes over parameter combinations (required)
  4. Dry-run one parameter combination to compile the indicator ahead of the distribution (optional)
  5. If the indicator is not compiled with Numba, divide parameter combinations into an optimal number of chunks, and execute all chunks in parallel with multiprocessing (i.e., one chunk per process) while executing all parameter combinations within each chunk serially

Registration

Custom indicators can be registered by the indicator factory to appear in the list of all indicators. This is convenient to be able to refer to the indicator by its name when running a data instance. Upon registration, you can assign the indicator to a custom location (the default location is "custom"), which acts as a tag or group; this can be used to build arbitrary indicator groups. One indicator can be assigned to multiple locations. Custom indicators have priority over built-in indicators.

vbt.IF.register_custom_indicator(sma_indicator)  # (1)!
vbt.IF.register_custom_indicator(sma_indicator, "SMA")  # (2)!
vbt.IF.register_custom_indicator(sma_indicator, "SMA", location="rolling")  # (3)!
vbt.IF.register_custom_indicator(sma_indicator, "rolling:SMA")
vbt.IF.register_custom_indicator("talib:sma", location="rolling")  # (4)!

vbt.IF.deregister_custom_indicator("SMA", location="rolling")  # (5)!
vbt.IF.deregister_custom_indicator("rolling:SMA")
vbt.IF.deregister_custom_indicator("SMA")  # (6)!
vbt.IF.deregister_custom_indicator(location="rolling")  # (7)!
vbt.IF.deregister_custom_indicator()  # (8)!
  1. Register an indicator class. The class name will become the indicator name.
  2. Register an indicator class with a specific name
  3. Register an indicator class with a specific name and under a specific location
  4. Assign a built-in indicator class to a custom location (i.e., tagging)
  5. Deregister all indicators with a specific name under a specific location
  6. Deregister all indicators with a specific name under all locations
  7. Deregister all indicators under a specific location
  8. Deregister all indicators under all locations