QQQ, VTI, and TLT 3-Asset Portfolio Rebalancing Backtest (Full Guide + Python Code)
QQQ, VTI, and TLT 3-Asset Portfolio Rebalancing Backtest (Full Guide + Python Code)
Discover how a 3-asset portfolio of QQQ, VTI, and TLT performs under monthly and quarterly rebalancing strategies. Includes CAGR, volatility, and MDD comparison with Python code you can run for free on Google Colab.
Introduction
For long-term investors, portfolio rebalancing is a powerful yet often overlooked tool. By periodically adjusting your asset allocation back to target weights, you can manage risk, control drawdowns, and even improve returns.
In this guide, we will:
- Introduce QQQ, VTI, and TLT as a diversified portfolio
- Run a backtest from 2010 to 2025 using free tools
- Compare monthly vs quarterly rebalancing performance
- Provide ready-to-run Python code in Google Colab
1. Portfolio Overview
| Ticker | Asset Class | Description |
|---|---|---|
| QQQ | US Large-Cap Growth | Tracks the Nasdaq-100 Index, heavily weighted in tech stocks. |
| VTI | Total US Stock Market | Includes large-, mid-, and small-cap US stocks. |
| TLT | US Long-Term Treasury Bonds | 20+ year maturity Treasuries; provides downside protection. |
2. Data Download (Google Colab)
# !pip install yfinance pandas numpy matplotlib --quiet
import yfinance as yf
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
tickers = ["QQQ", "VTI", "TLT"]
start, end = "2010-01-01", "2025-01-01"
prices = yf.download(tickers, start=start, end=end)["Adj Close"].dropna()
returns = prices.pct_change().dropna()
prices.tail()
3. Rebalancing Backtest Function
def rebalance_backtest(prices, target_weights, freq="M", fee=0.0005):
rets = prices.pct_change().fillna(0.0)
if freq == "M":
rebal_dates = prices.resample("M").last().index
elif freq == "Q":
rebal_dates = prices.resample("Q").last().index
else:
raise ValueError("freq must be M or Q")
cols = list(target_weights.keys())
weights = pd.Series(target_weights, index=cols, dtype=float)
port_val = 1.0
holdings = (weights * port_val) / prices.iloc[0][cols]
port_vals = []
for i in range(1, len(prices)):
day_ret = (prices.iloc[i][cols] / prices.iloc[i-1][cols]) - 1.0
holdings *= (1 + day_ret)
port_val = (holdings * prices.iloc[i][cols]).sum()
if prices.index[i] in rebal_dates:
current_weights = (holdings * prices.iloc[i][cols]) / port_val
turnover = (current_weights - weights).abs().sum()
cost = port_val * fee * turnover
port_val -= cost
holdings = (weights * port_val) / prices.iloc[i][cols]
port_vals.append(port_val)
return pd.Series(port_vals, index=prices.index[1:])
4. Running the Backtest
target = {"QQQ":0.4, "VTI":0.4, "TLT":0.2}
eq_M = rebalance_backtest(prices, target, freq="M")
eq_Q = rebalance_backtest(prices, target, freq="Q")
def cagr(series):
yrs = (series.index[-1] - series.index[0]).days / 365.25
return (series.iloc[-1] / series.iloc[0]) ** (1/yrs) - 1
def vol(series):
return series.pct_change().std() * np.sqrt(252)
def mdd(series):
return ((series / series.cummax()) - 1).min()
summary = pd.DataFrame({
"Monthly": [cagr(eq_M), vol(eq_M), mdd(eq_M)],
"Quarterly": [cagr(eq_Q), vol(eq_Q), mdd(eq_Q)]
}, index=["CAGR","Volatility","MDD"])
print(summary)
plt.figure(figsize=(10,5))
(eq_M/eq_M.iloc[0]).plot(label="Monthly")
(eq_Q/eq_Q.iloc[0]).plot(label="Quarterly")
plt.legend()
plt.title("QQQ·VTI·TLT Portfolio Backtest")
plt.ylabel("Equity (Index=1)")
plt.grid(True)
plt.show()
5. Key Findings
- Monthly rebalancing slightly reduces volatility but incurs higher trading costs.
- Quarterly rebalancing saves costs with similar long-term returns.
- Including TLT (20% allocation) significantly reduces maximum drawdown (MDD).
6. Practical Tips
- Consider adding bonds if your portfolio is heavy on tech/growth stocks.
- Match your rebalancing frequency to market volatility and trading fees.
- Review and adjust your allocation at least once a year.
FAQ
Q1: Can I trade these ETFs outside the US?
Yes, most brokers worldwide allow trading of QQQ, VTI, and TLT through international accounts.
Q2: Which rebalancing period is better?
It depends on volatility and costs. Monthly is more responsive, quarterly is more cost-efficient.
Q3: Is TLT still a good hedge in rising rate environments?
Long-term Treasuries can lose value when rates rise, but they often rally in equity bear markets.
📥 Free Resources: Download the Google Colab template and a ready-made portfolio PDF from the link below. Perfect for backtesting your own assets.
🎯 Recommended Broker: Click here for low-fee ETF trading accounts.