Features
Portfolio accounting
Track positions, weights, records, deposits, earnings, and portfolio state
✅ Asset weighting lets you fine-tune the influence of individual assets or strategies within your portfolio, giving you enhanced control over your portfolio's overall performance. The key benefit is that these weights are not limited to returns—they are consistently applied to all time series and metrics, including orders, cash flows, and more. This comprehensive approach ensures that every aspect of your portfolio stays precisely aligned.
data = vbt.YFData.pull(["AAPL", "MSFT", "GOOG"], start="2020")
pf = data.run("from_random_signals", n=vbt.Default(50), seed=42, group_by=True)
pf.get_sharpe_ratio(group_by=False) symbol
AAPL 1.401012
MSFT 0.456162
GOOG 0.852490
Name: sharpe_ratio, dtype: float64pf.sharpe_ratio 1.2132857343006869prices = pf.get_value(group_by=False)
weights = vbt.pypfopt_optimize(prices=prices)
weights{'AAPL': 0.85232, 'MSFT': 0.0, 'GOOG': 0.14768}weighted_pf = pf.apply_weights(weights, rescale=True)
weighted_pf.weightssymbol
AAPL 2.55696
MSFT 0.00000
GOOG 0.44304
dtype: float64weighted_pf.get_sharpe_ratio(group_by=True) 1.426112580298898✅ Position views let you analyze your portfolio by focusing on either long or short positions, providing a clear and distinct perspective for each investment strategy.
data = vbt.YFData.pull("BTC-USD")
fast_sma = data.run("talib_func:sma", timeperiod=20)
slow_sma = data.run("talib_func:sma", timeperiod=50)
long_entries = fast_sma.vbt.crossed_above(slow_sma)
short_entries = fast_sma.vbt.crossed_below(slow_sma)
pf = vbt.PF.from_signals(
data,
long_entries=long_entries,
short_entries=short_entries,
fees=0.01,
fixed_fees=1.0
)
long_pf = pf.long_view
short_pf = pf.short_view
fig = vbt.make_subplots(rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.01)
fig = long_pf.assets.vbt.plot_against(
0,
trace_kwargs=dict(name="Long position", line_shape="hv", line_color="mediumseagreen"),
other_trace_kwargs=dict(visible=False),
add_trace_kwargs=dict(row=1, col=1),
fig=fig
)
fig = short_pf.assets.vbt.plot_against(
0,
trace_kwargs=dict(name="Short position", line_shape="hv", line_color="coral"),
other_trace_kwargs=dict(visible=False),
add_trace_kwargs=dict(row=2, col=1),
fig=fig
)
fig.show()long_pf.sharpe_ratio0.9185961894435091short_pf.sharpe_ratio0.2760864152147919✅ How can you backtest time- and asset-anchored queries such as "Order X units of asset Y on date Z"? Typically, you would need to build a full array and set each detail manually. Now, there is a simpler way: with preparers and redesigned smart indexing, you can provide all information in a compressed record format! Behind the scenes, the record array is translated into a set of index dictionaries—one for each argument.
data = vbt.YFData.pull(["BTC-USD", "ETH-USD"], missing_index="drop")
records = [
dict(date="2022", symbol="BTC-USD", long_entry=True),
dict(date="2022", symbol="ETH-USD", short_entry=True),
dict(row=-1, exit=True),
]
pf = vbt.PF.from_signals(data, records=records)
pf.orders.readable Order Id Column Signal Index Creation Index
0 0 BTC-USD 2022-01-01 00:00:00+00:00 2022-01-01 00:00:00+00:00 \
1 1 BTC-USD 2023-04-25 00:00:00+00:00 2023-04-25 00:00:00+00:00
2 0 ETH-USD 2022-01-01 00:00:00+00:00 2022-01-01 00:00:00+00:00
3 1 ETH-USD 2023-04-25 00:00:00+00:00 2023-04-25 00:00:00+00:00
Fill Index Size Price Fees Side Type
0 2022-01-01 00:00:00+00:00 0.002097 47686.812500 0.0 Buy Market \
1 2023-04-25 00:00:00+00:00 0.002097 27534.675781 0.0 Sell Market
2 2022-01-01 00:00:00+00:00 0.026527 3769.697021 0.0 Sell Market
3 2023-04-25 00:00:00+00:00 0.026527 1834.759644 0.0 Buy Market
Stop Type
0 None
1 None
2 None
3 None✅ Dynamic signal functions now have access to the current position information, such as (open) P&L.
@njit
def signal_func_nb(ctx, entries, exits):
is_entry = vbt.pf_nb.select_nb(ctx, entries)
is_exit = vbt.pf_nb.select_nb(ctx, exits)
if is_entry:
return True, False, False, False
if is_exit:
pos_info = ctx.last_pos_info[ctx.col]
if pos_info["status"] == vbt.pf_enums.TradeStatus.Open:
if pos_info["pnl"] >= 0:
return False, True, False, False
return False, False, False, False
data = vbt.YFData.pull("BTC-USD")
entries, exits = data.run("RANDNX", n=10, seed=42, unpack=True)
pf = vbt.Portfolio.from_signals(
data,
signal_func_nb=signal_func_nb,
signal_args=(vbt.Rep("entries"), vbt.Rep("exits")),
broadcast_named_args=dict(entries=entries, exits=exits),
jitted=False
)
pf.trades.readable[["Entry Index", "Exit Index", "PnL"]] Entry Index Exit Index PnL
0 2014-11-01 00:00:00+00:00 2016-01-08 00:00:00+00:00 39.134739
1 2016-03-27 00:00:00+00:00 2016-09-07 00:00:00+00:00 61.220063
2 2016-12-24 00:00:00+00:00 2016-12-31 00:00:00+00:00 14.471414
3 2017-03-16 00:00:00+00:00 2017-08-05 00:00:00+00:00 373.492028
4 2017-09-12 00:00:00+00:00 2018-05-05 00:00:00+00:00 815.699284
5 2019-02-15 00:00:00+00:00 2019-11-10 00:00:00+00:00 2107.383227
6 2019-12-04 00:00:00+00:00 2019-12-10 00:00:00+00:00 12.630214
7 2020-07-12 00:00:00+00:00 2021-11-14 00:00:00+00:00 21346.035444
8 2022-01-15 00:00:00+00:00 2023-03-06 00:00:00+00:00 -11925.133817✅ Cash can be deposited or withdrawn at any time.
data = vbt.YFData.pull("BTC-USD")
cash_deposits = data.symbol_wrapper.fill(0.0)
month_start_mask = ~data.index.tz_convert(None).to_period("M").duplicated()
cash_deposits[month_start_mask] = 10
pf = vbt.PF.from_orders(
data.close,
init_cash=0,
cash_deposits=cash_deposits
)
pf.input_value 1020.0pf.final_value20674.328828315127✅ Cash can be continuously earned or spent depending on the current position.
data = vbt.YFData.pull("AAPL", start="2010")
pf_kept = vbt.PF.from_holding(
data.close,
cash_dividends=data.get("Dividends")
)
pf_kept.cash.iloc[-1] 93.9182408043298pf_kept.assets.iloc[-1] 15.37212731743495pf_reinvested = vbt.PF.from_orders(
data.close,
cash_dividends=data.get("Dividends")
)
pf_reinvested.cash.iloc[-1]0.0pf_reinvested.assets.iloc[-1]18.203284859405468fig = pf_kept.value.rename("Value (kept)").vbt.plot()
pf_reinvested.value.rename("Value (reinvested)").vbt.plot(fig=fig)
fig.show()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.