Skip to content

Backtesting a Simple Fixed Ratio Portfolio with TiPortfolio

I have been building a Python backtesting library called TiPortfolio for a while now. It is designed to be simple but flexible enough to test real portfolio strategies. This is the first of a series of posts where I walk through each example notebook.

Let me start with the most basic strategy: a fixed ratio portfolio rebalanced monthly.

The Strategy

The portfolio holds three ETFs with fixed weights:

  • QQQ (Nasdaq 100) — 70%
  • BIL (short-term treasury) — 20%
  • GLD (gold) — 10%

Every end of month, it rebalances back to those weights. That is it.

In TiPortfolio, the algo stack follows a Signal → Select → Weigh → Action pattern. Each step is composable, so you can mix and match later.

portfolio = ti.Portfolio(
    "monthly_70_20_10",
    [
        ti.Signal.Monthly(),
        ti.Select.All(),
        ti.Weigh.Ratio(weights={"QQQ": 0.7, "BIL": 0.2, "GLD": 0.1}),
        ti.Action.Rebalance(),
    ],
    TICKERS,
)

result = ti.run(ti.Backtest(portfolio, data))

Running a backtest is one line. The result object gives you everything.

Results (2019–2024)

sharpe          0.642
calmar          0.546
sortino         0.833
max_drawdown   -0.264
cagr            0.144
total_return    1.559
final_value    25588.316
total_fee       0.939
rebalance_count 83

Starting from $10,000, the portfolio grew to about $25,600 over 6 years with a 14.4% CAGR. The max drawdown was -26.4%, which happened during 2022 when both equities and bonds sold off at the same time.

The Sharpe ratio of 0.64 is decent — not amazing, but the portfolio was holding 30% in defensive assets (BIL + GLD), so it is expected to lag a pure equity portfolio in returns.

How It Compares

I ran two baselines alongside it:

                  monthly_70_20_10   qqq_only   never_rebalanced
sharpe                       0.642      0.684              0.669
max_drawdown                -0.264     -0.351             -0.302
cagr                         0.144      0.192              0.160
final_value              25588.316  34106.625          28127.486
total_fee                    0.939      0.233              0.284

QQQ-only won on returns (19.2% CAGR vs 14.4%) but with a much worse max drawdown (-35.1% vs -26.4%). The monthly rebalancing strategy gave up some return in exchange for a smoother ride.

Interestingly, the "never rebalanced" portfolio performed between the two — it drifted towards more QQQ over time as QQQ outperformed, so it ended up with better returns than the fixed-ratio version but worse drawdowns.

My Take

This is the strategy most personal finance guides recommend, and the backtest confirms why: it is simple, cheap to run (only 0.939 total in fees over 6 years), and gives you predictable risk exposure.

The trade-off is clear though — if QQQ keeps outperforming, you are constantly trimming your winner. The rebalancing premium works best in mean-reverting markets.

I use this as the baseline for everything else. The next posts will show more sophisticated weighting methods and whether they actually improve things.


This Series

🤞Subscribe if you want to see more!

We don’t spam! Read more in our privacy policy

Leave a Reply

Your email address will not be published. Required fields are marked *