Features

Trading signals

Detect, unravel, and analyze pivots, crossovers, and trading signals

Signal unraveling

✅ To backtest each signal individually, you can now "unravel" each signal, or each pair of entry and exit signals, into its own column. This creates a wide, two-dimensional mask that, when backtested, returns performance metrics for each signal rather than for the entire column.

For each signal, create a separate position with own stop orders
data = vbt.YFData.pull("BTC-USD")
fast_sma = data.run("talib_func:sma", timeperiod=20)  
slow_sma = data.run("talib_func:sma", timeperiod=50)
entries = fast_sma.vbt.crossed_above(slow_sma)
exits = fast_sma.vbt.crossed_below(slow_sma)
entries, exits = entries.vbt.signals.unravel_between(exits, relation="anychain")  
pf = vbt.PF.from_signals(
    data,
    long_entries=entries,
    short_entries=exits,
    size=100,  
    size_type="value",
    init_cash="auto",  
    tp_stop=0.2,
    sl_stop=0.1,
    group_by=vbt.ExceptLevel("signal"),  
    cash_sharing=True
)
pf.positions.returns.to_pd(ignore_index=True).vbt.barplot(
    trace_kwargs=dict(marker=dict(colorscale="Spectral"))
).show()  
Position returns for individually unraveled BTC-USD signals Figure data (JSON)

Signal detection

✅ VBT includes an indicator that uses a robust peak detection algorithm based on z-scores. This indicator can be used to identify outbreaks and outliers in any time series data.

Detect sudden changes in the bandwidth of a Bollinger Bands indicator
data = vbt.YFData.pull("BTC-USD")
fig = vbt.make_subplots(rows=2, cols=1, shared_xaxes=True)
bbands = data.run("bbands")
bbands.loc["2022"].plot(add_trace_kwargs=dict(row=1, col=1), fig=fig)
sigdet = vbt.SIGDET.run(bbands.bandwidth, factor=5)
sigdet.loc["2022"].plot(add_trace_kwargs=dict(row=2, col=1), fig=fig)
fig.show()
BTC-USD Bollinger Bands and detected bandwidth changes during 2022 Figure data (JSON)

Pivot detection

✅ The pivot detection indicator is a tool for finding when the price trend is reversing. By identifying support and resistance areas, it helps spot significant price changes while filtering out short-term fluctuations and reducing noise. It works simply: a peak is registered when the price jumps above one threshold, and a valley is recorded when the price falls below another. Another advantage is that, unlike the regular Zig Zag indicator, which tends to look ahead, our indicator only returns confirmed pivot points and is safe to use in backtesting.

Plot the last pivot value
data = vbt.YFData.pull("BTC-USD", start="2020", end="2023")
fig = data.plot(plot_volume=False)
pivot_info = data.run("pivotinfo", up_th=1.0, down_th=0.5)
pivot_info.plot(fig=fig, conf_value_trace_kwargs=dict(visible=False))
fig.show()
BTC-USD OHLC with confirmed pivot values from 2020 through 2022 Figure data (JSON)

✅ Crossovers are now robust to NaNs.

Remove a bunch of data points and plot the crossovers
data = vbt.YFData.pull("BTC-USD", start="2022-01", end="2022-03")
fast_sma = vbt.talib("SMA").run(data.close, vbt.Default(5)).real
slow_sma = vbt.talib("SMA").run(data.close, vbt.Default(10)).real
np.random.seed(42)
fast_sma.iloc[np.random.choice(np.arange(len(fast_sma)), 5)] = np.nan
slow_sma.iloc[np.random.choice(np.arange(len(slow_sma)), 5)] = np.nan
crossed_above = fast_sma.vbt.crossed_above(slow_sma, skipna=True)
crossed_below = fast_sma.vbt.crossed_below(slow_sma, skipna=True)

fig = fast_sma.rename("Fast SMA").vbt.lineplot()
slow_sma.rename("Slow SMA").vbt.lineplot(fig=fig)
crossed_above.vbt.signals.plot_as_entries(fast_sma, fig=fig)
crossed_below.vbt.signals.plot_as_exits(fast_sma, fig=fig)
fig.show()
Robust fast and slow BTC-USD moving-average crossovers with missing data Figure data (JSON)

Copyright © 20212026 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.