Writing / October 28, 2026
Somewhere Between Active and Passive Investing
I like the idea of buying the S&P 500 and leaving it alone. I like it a little less when I imagine watching half my portfolio disappear in a crash.
The usual alternatives I hear about are picking stocks or trying to time the market with charts. Neither sounds like something I want to do every day. Then I came across tactical asset allocation, and found an idea that felt much more approachable: write down a rule for when to hold stocks and when to step aside.
The first rule I tried was pretty simple. If SPY, an ETF tracking the S&P 500, has a positive return over the past year, hold it. Otherwise, hold BIL, a short-term Treasury bill ETF. I wanted to see what would happen if I just followed that rule every month instead of making a fresh prediction.
Interactive demo loading. JavaScript is required to use it.
Well, that’s a tradeoff! In this particular history, the rule made the worst fall smaller, but buying and holding SPY ended up much further ahead. Getting out can help during a decline; it can also leave you watching a recovery from the sidelines.
That’s what caught my attention. I can make an active decision about what I hold without spending every morning staring at a chart. And as a software engineer, I can actually write the decision down and experiment with it. Naturally, the next thing I wanted to do was build a backtest.
The backtest was cheating
The rule sounded easy to code: look at SPY’s return over the past year at month-end, then buy SPY or BIL.
But there’s a subtle problem with when the trade happens.
If I use the month-end closing price to calculate the signal, I only know what to buy after the market has closed. I can’t assume I also traded at that same closing price.
It sounds like a minor detail, but here’s what happened when I compared the two execution assumptions.
Interactive demo loading. JavaScript is required to use it.
Using the same closing price for both the signal and the trade gave me a 10.8% annualized return and a −19.6% maximum drawdown. Moving execution to the next session’s close changed those numbers to 10.3% and −24.0%.
That’s lookahead bias. The code runs correctly, and the results look plausible, but the simulation is using information that wasn’t available when the trade supposedly happened.
For my SPY and TIP experiments, I calculate signals after month-end and use the next trading session’s close for execution. That’s still a modeling assumption, not a guarantee of what a real order would achieve. I also account for distributions and charge 0.1% per transaction side.
The SPY comparison covers 218 holding periods, from the July 2008 signal through the August 2026 signal. Drawdowns are measured at monthly execution dates, so intramonth declines may not be visible.
And execution timing is just one thing to get right. Historical prices can be revised, index membership changes, and fundamental data may not have been available when a simulated decision was made.
Writing the rule was straightforward. Making sure the backtest was testing that rule fairly took more care.
A great backtest, then what?
Once I had a chart, I wanted to know how much faith to put in it. I went looking for a rule that had been published with a long backtest, so I could also look at what came afterward.
One example is Gary Antonacci’s Global Equities Momentum, or GEM, from his 2014 book. It looks at the past year’s returns. If US stocks beat Treasury bills, it holds whichever of US or international stocks did better. Otherwise, it moves to US bonds. The book’s original backtest ran from 1974 through 2013.
Interactive demo loading. JavaScript is required to use it.
The difference between those two periods surprised me. In this reconstruction, GEM returns 16.6% a year in the earlier period, compared with 11.0% for US stocks. From 2015 through July 2026, it returns 8.4%, while US stocks return 13.7%. GEM’s monthly maximum drawdown is a little smaller in the later period, so the return isn’t the whole story.
There’s a catch: this reconstruction uses the month-end signal close as its trade price, the very timing problem I just mentioned. It also uses reconstructed historical indexes and no trading costs. So I wouldn’t put too much weight on the exact figures. Still, seeing the later period is a useful reminder that a rule doesn’t get to choose what the market does next. This alone doesn’t prove that GEM was overfit.
Can I automate the boring part?
Once I’ve decided on a rule, running it every month sounds like a job for a computer. Wait for the month to close, fetch the prices, calculate the allocation, and tell me what changed. Something roughly like this:
after month_end_close:
prices = refresh_prices()
if prices.are_missing_or_stale:
stop_and_report()
past_year_return = prices.SPY / price_12_months_ago - 1
target = SPY if past_year_return > 0 else BIL
changes = compare(target, account.holdings)
save(prices, target, changes)
notify(changes)
Sometimes that means holding the same ETF for another month. With a portfolio of several assets, even unchanged target weights might need a rebalance because the holdings have drifted as prices moved.
I built a web app for this: I can choose a strategy, look through its backtest, and subscribe to a monthly email with the next allocation. I like the idea of having the routine taken care of while I spend my time thinking about the rule itself.
A brokerage API could take this further and place orders too. I’d want to try that in paper trading first. Stale prices, rejected orders, and a retry that submits the same trade twice are much less entertaining with real money. I’d also need to check what actually filled against what the account was supposed to hold.
A canary for stocks?
After looking at SPY’s own trend, I stumbled on a question I hadn’t thought to ask: could a completely different asset tell me something useful about when to hold SPY?
Wouter Keller and JW Keuning’s Hybrid Asset Allocation gave me a fun example. Their simplified HAA-Simple rule uses TIP, an ETF holding Treasury Inflation-Protected Securities, as a “canary.” Even if SPY’s trend is positive, a weak TIP trend can keep the strategy out of stocks.
TIP isn’t an inflation meter, though. The bonds’ principal adjusts with inflation, but the ETF’s price also moves with real interest rates and duration. That makes the question more interesting to me: does its price happen to contain information about what stocks do next?
HAA-Simple measures trend a little differently from my first experiment. It averages the past 1-, 3-, 6-, and 12-month returns. When both SPY and TIP are positive, it holds SPY. Otherwise, it picks the stronger trend between BIL and IEF, an intermediate-term Treasury ETF. The implementation notes have the details.
Before comparing strategies, I wanted to see what SPY actually did after each combination of signals. Each cell has its average return over the following holding period, the number of months, and the worst drawdown after joining those selected monthly returns together.
| TIP up | TIP down | |
|---|---|---|
| SPY up | Average: 1.36% Max DD: −17.48% Count: 144 months | Average: −0.08% Max DD: −36.78% Count: 39 months |
| SPY down | Average: 2.48% Max DD: −19.89% Count: 16 months | Average: 0.55% Max DD: −30.97% Count: 19 months |
That’s interesting! In this sample, when TIP’s trend was up, SPY’s next return was higher on average and the joined-up drawdown was smaller, whether SPY’s own trend was up or down. But there are only 16 and 19 months in the SPY-down groups. And those drawdowns join selected months that weren’t necessarily consecutive; they aren’t the drawdowns of a portfolio I could have held.
This also made me wonder: what if I followed TIP’s trend alone? The chart compares that with SPY’s trend, both trends together, and plain old buy-and-hold. All three trend rules use the same calculation and the same BIL-or-IEF choice when defensive.
Interactive demo loading. JavaScript is required to use it.
In this history, following TIP alone has the highest return: 13.6% a year, compared with 11.5% for requiring both signals. Its monthly maximum drawdown is deeper, though: 23.8% versus 17.3%. At this point I was tempted to throw out the SPY signal.
Then I looked at Keller and Keuning’s longer backtest. Over 1970–2022, their TIP-only version had a 44.7% maximum drawdown, versus 16.6% with both signals. Their annualized returns were 12.6% and 12.8%. That’s a very different picture. It also comes with a big caveat: the history starts before these ETFs existed, and even before TIPS were introduced in 1997, so the earlier data is reconstructed. The dates and assumptions differ from my chart too.
I don’t think this settles whether TIP will help in the future. It does give me another question to investigate, which is how I ended up here in the first place. There’s more to read on cross-asset signals, Faber’s moving-average research, and at Allocate Smartly and TrendXplorer.
I started by wondering if I could avoid some stock-market crashes without becoming a full-time chart watcher. I ended up writing trading rules, learning how easily a backtest can mislead me, and looking at a bond ETF as a possible stock-market canary. I still don’t know which rule will look best over the next decade. But I’ve had a lot of fun exploring a part of investing I didn’t know existed.