Features

Analysis

Inspect trades, patterns, projections, benchmarks, and excursion metrics

Simulation ranges

✅ Each simulation starts and ends at specific points, usually matching the first and last rows of your data. You can set a different simulation range beforehand, and now, you can also adjust this range during the simulation. This flexibility lets you stop the simulation when further processing is unnecessary. Additionally, the date range is saved in the portfolio object, so all metrics and subplots recognize it. Processing only the relevant dates speeds up execution and adds a new dimension to your analysis: isolated time windows 🔬

Simulate a quick liquidation scenario
@njit
def post_segment_func_nb(ctx):
    value = vbt.pf_nb.get_group_value_nb(ctx, ctx.group)
    if value <= 0:
        vbt.pf_nb.stop_group_sim_nb(ctx, ctx.group)  

pf = vbt.PF.from_random_signals(
    "BTC-USD",
    n=10,
    seed=42,
    sim_start="auto",  
    post_segment_func_nb=post_segment_func_nb,
    leverage=10,
)
pf.plot_value()  
Seeded leveraged BTC-USD portfolio value through liquidation Figure data (JSON)

✅ Regular metrics like MAE and MFE only represent the final point of each trade. But what if you want to see how these metrics develop during the trade? You can now analyze expanding trade metrics as DataFrames!

Visualize the expanding MFE using projections
data = vbt.YFData.pull("BTC-USD")
pf = vbt.PF.from_random_signals(data, n=50, tp_stop=0.5, seed=42)
pf.trades.plot_expanding_mfe_returns().show()
Expanding maximum favorable excursion return projections for BTC-USD trades Figure data (JSON)

Trade signals

✅ New trade plotting method that separates entry and exit trades into long entries, long exits, short entries, and short exits. It supports different styles for positions.

Plot trade signals of a Bollinger Bands strategy
data = vbt.YFData.pull("BTC-USD")
bb = data.run("bbands")
long_entries = data.hlc3.vbt.crossed_above(bb.upper) & (bb.bandwidth < 0.1)
long_exits = data.hlc3.vbt.crossed_below(bb.upper) & (bb.bandwidth > 0.5)
short_entries = data.hlc3.vbt.crossed_below(bb.lower) & (bb.bandwidth < 0.1)
short_exits = data.hlc3.vbt.crossed_above(bb.lower) & (bb.bandwidth > 0.5)
pf = vbt.PF.from_signals(
    data,
    long_entries=long_entries,
    long_exits=long_exits,
    short_entries=short_entries,
    short_exits=short_exits
)
pf.plot_trade_signals().show()
BTC-USD OHLC with long and short Bollinger Bands strategy trade signals Figure data (JSON)

Edge ratio

Edge ratio is a unique metric for quantifying entry profitability. Unlike most performance metrics, the edge ratio accounts for both open profits and losses. This can help you find better trade exits.

Compare the edge ratio of an EMA crossover to a random strategy
data = vbt.YFData.pull("BTC-USD")
fast_ema = data.run("ema", 10, hide_params=True)
slow_ema = data.run("ema", 20, hide_params=True)
entries = fast_ema.real_crossed_above(slow_ema)
exits = fast_ema.real_crossed_below(slow_ema)
pf = vbt.PF.from_signals(data, entries, exits, direction="both")
rand_pf = vbt.PF.from_random_signals(data, n=pf.orders.count() // 2, seed=42)  
fig = pf.trades.plot_running_edge_ratio(
    trace_kwargs=dict(line_color="limegreen", name="Edge Ratio (S)")
)
fig = rand_pf.trades.plot_running_edge_ratio(
    trace_kwargs=dict(line_color="mediumslateblue", name="Edge Ratio (R)"),
    fig=fig
)
fig.show()
Running edge ratios for EMA crossover and random BTC-USD strategies Figure data (JSON)

Trade history

✅ Trade history is a human-readable DataFrame listing orders, extended with useful details about entry trades, exit trades, and positions.

Get the trade history of a random portfolio with one signal
data = vbt.YFData.pull(["BTC-USD", "ETH-USD"], missing_index="drop")
pf = vbt.PF.from_random_signals(
    data,
    n=1,
    seed=42,
    run_kwargs=dict(hide_params=True),
    tp_stop=0.5,
    sl_stop=0.1
)
pf.trade_history
   Order Id   Column              Signal Index            Creation Index  \
0         0  BTC-USD 2016-02-20 00:00:00+00:00 2016-02-20 00:00:00+00:00
1         1  BTC-USD 2016-02-20 00:00:00+00:00 2016-06-12 00:00:00+00:00
2         0  ETH-USD 2019-05-25 00:00:00+00:00 2019-05-25 00:00:00+00:00
3         1  ETH-USD 2019-05-25 00:00:00+00:00 2019-07-15 00:00:00+00:00

                 Fill Index  Side    Type Stop Type      Size       Price  \
0 2016-02-20 00:00:00+00:00   Buy  Market      None  0.228747  437.164001
1 2016-06-12 00:00:00+00:00  Sell  Market        TP  0.228747  655.746002
2 2019-05-25 00:00:00+00:00   Buy  Market      None  0.397204  251.759872
3 2019-07-15 00:00:00+00:00  Sell  Market        SL  0.397204  226.583885

   Fees   PnL  Return Direction  Status  Entry Trade Id  Exit Trade Id  \
0   0.0  50.0     0.5      Long  Closed               0             -1
1   0.0  50.0     0.5      Long  Closed              -1              0
2   0.0 -10.0    -0.1      Long  Closed               0             -1
3   0.0 -10.0    -0.1      Long  Closed              -1              0

   Position Id
0            0
1            0
2            0
3            0

Patterns

✅ Patterns are distinctive formations created by price movements on a chart and are central to technical analysis. There are now new dedicated functions and classes for detecting patterns of any complexity in any type of time series data. The idea is simple: fit a pattern to align with the scale and period of your selected data window, then compute the element-wise distance between them to get a single similarity score. You can adjust the threshold for this score to decide above which value a data window should be marked as "matched." Thanks to Numba, this operation can be performed hundreds of thousands of times per second! 🔎

Find and plot a descending triangle pattern
data = vbt.YFData.pull("BTC-USD")
data.hlc3.vbt.find_pattern(
    pattern=[5, 1, 3, 1, 2, 1],
    window=100,
    max_window=700,
).loc["2017":"2019"].plot().show()
Descending triangle pattern matches in BTC-USD from 2017 through 2019 Figure data (JSON)

Tutorial

Learn more in the Patterns and projections tutorial.

Projections

✅ There are cleaner ways to analyze events and their impact on price than conventional backtesting. Meet projections! 👋 Not only can they help you assess event performance visually and quantitatively, but they can also project events into the future to support trading. This is done by extracting the price range after each event, collecting all these price ranges into a multidimensional array, and then deriving confidence intervals and other useful statistics from that array. When combined with patterns, these tools are a quantitative analyst's dream! 🌟

Find occurrences of the price moving similarly to the last week and project them
data = vbt.YFData.pull("ETH-USD")
pattern_ranges = data.hlc3.vbt.find_pattern(
    pattern=data.close.iloc[-7:],
    rescale_mode="rebase"
)
delta_ranges = pattern_ranges.with_delta(7)
fig = data.iloc[-7:].plot(plot_volume=False)
delta_ranges.plot_projections(fig=fig)
fig.show()
ETH-USD last-week pattern matches with projected confidence bands Figure data (JSON)

Tutorial

Learn more in the Patterns and projections tutorial.

MAE and MFE

Maximum Adverse Excursion (MAE) helps you see the maximum loss taken during a trade, also known as the maximum drawdown of the position. Maximum Favorable Excursion (MFE) shows the highest profit reached during a trade. Analyzing MAE and MFE statistics can help you improve your exit strategies.

Analyze the MAE of a random portfolio without SL
data = vbt.YFData.pull("BTC-USD")
pf = vbt.PF.from_random_signals(data, n=50, seed=42)
pf.trades.plot_mae_returns().show()
Maximum adverse excursion versus return for BTC-USD trades without stop loss Figure data (JSON)
Analyze the MAE of a random portfolio with SL
pf = vbt.PF.from_random_signals(data, n=50, sl_stop=0.1, seed=42)
pf.trades.plot_mae_returns().show()
Maximum adverse excursion versus return for BTC-USD trades with stop loss Figure data (JSON)

✅ Previously, OHLC data was used for simulation, but only the close price was analyzed. Now, most classes let you track all OHLC data for more accurate quantitative and qualitative analysis.

Plot trades of a random portfolio
data = vbt.YFData.pull("BTC-USD", start="2020-01", end="2020-03")
pf = vbt.PF.from_random_signals(
    open=data.open,
    high=data.high,
    low=data.low,
    close=data.close,
    n=10,
    seed=42
)
pf.trades.plot().show()
BTC-USD OHLC with random portfolio trade entries and exits Figure data (JSON)

Benchmark

✅ The benchmark can now be easily set for your entire portfolio.

Compare Microsoft to S&P 500
data = vbt.YFData.pull(["SPY", "MSFT"], start="2010", missing_columns="drop")

pf = vbt.PF.from_holding(
    close=data.data["MSFT"]["Close"],
    bm_close=data.data["SPY"]["Close"]
)
pf.plot_cumulative_returns().show()
Cumulative returns of Microsoft compared with the S&P 500 benchmark Figure data (JSON)

And many more...

⏩ Look forward to more killer features being added every release!

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.