Comparing results
Comparing Results
ti.run() accepts multiple Backtest objects. When more than one is passed, all result methods automatically switch to comparison mode — metrics become a DataFrame and charts overlay all portfolios.
Side-by-Side Comparison
import tiportfolio as ti
tickers = ["QQQ", "BIL", "GLD"]
data = ti.fetch_data(tickers, start="2019-01-01", end="2024-12-31")
monthly = ti.Backtest(
ti.Portfolio('monthly', [ti.Signal.Monthly(), ti.Select.All(), ti.Weigh.Equally(), ti.Action.Rebalance()], tickers),
data,
)
quarterly = ti.Backtest(
ti.Portfolio('quarterly', [ti.Signal.Quarterly(), ti.Select.All(), ti.Weigh.Equally(), ti.Action.Rebalance()], tickers),
data,
)
yearly = ti.Backtest(
ti.Portfolio('yearly', [ti.Signal.Schedule(month=1), ti.Select.All(), ti.Weigh.Equally(), ti.Action.Rebalance()], tickers),
data,
)
result = ti.run(monthly, quarterly, yearly)
Summary Table
result.summary()
# Returns pd.DataFrame — rows are metrics, columns are portfolio names:
#
# monthly quarterly yearly
# total_return 0.42 0.39 0.35
# cagr 0.07 0.065 0.059
# sharpe 0.91 0.88 0.84
# max_drawdown -0.18 -0.19 -0.21
# ...
For the full metric set:
Overlaid Charts
result.plot() # equity curves on one chart, one line per portfolio
result.plot_histogram() # return distributions overlaid
result.plot_security_weights() # separate panel per portfolio
Accessing Individual Results
Both positional index and portfolio name work regardless of how many tests were run:
result[0] # first portfolio's BacktestResult
result["monthly"] # by portfolio name
result["quarterly"].summary() # individual summary DataFrame (single column)
result["quarterly"].trades # individual trades DataFrame
This means you can always write result[0] even for a single backtest, making it easy to add comparisons later without changing the rest of your code.
Comparing Allocation Strategies
A common pattern — test the same schedule with different weighting methods:
import pandas as pd
tickers = ["QQQ", "BIL", "GLD"]
data = ti.fetch_data(tickers, start="2019-01-01", end="2024-12-31")
def monthly_portfolio(name, weigh_algo):
return ti.Backtest(
ti.Portfolio(name, [ti.Signal.Monthly(), ti.Select.All(), weigh_algo, ti.Action.Rebalance()], tickers),
data,
)
result = ti.run(
monthly_portfolio("equal_weight", ti.Weigh.Equally()),
monthly_portfolio("fixed_ratio", ti.Weigh.Ratio(weights={"QQQ": 0.7, "BIL": 0.2, "GLD": 0.1})),
monthly_portfolio("vol_target", ti.Weigh.BasedOnHV(initial_ratio={"QQQ": 0.7, "BIL": 0.2, "GLD": 0.1}, target_hv=0.60, lookback=pd.DateOffset(months=1))),
monthly_portfolio("erc", ti.Weigh.ERC(lookback=pd.DateOffset(months=3))),
)
result.plot()
result.summary()