Mean Reversion vs Seasonality — Is the Turn-of-Month Effect Real After Costs?
Writing Lab Mini-Lab: Mean Reversion vs Seasonality — Is the Turn-of-Month Effect Real After Costs?
Mean reversion and seasonality are easy to overfit. Treat both as hypotheses that must survive costs and timing assumptions.
This mini-lab forces a small, testable claim:
Claim: equity index returns are systematically higher around month-end / month-start (“turn-of-month”), and you can harvest it with a simple calendar rule.
We’ll treat it as a lab, not a belief.
Toy strategy / idea
Pick a liquid index proxy (SPY, ES continuous futures, etc.). Define a calendar window around month-end. A common “turn-of-month” rule is:
- Long from the close of the last trading day of the month through the close of the 3rd trading day of the next month.
- Flat otherwise.
That’s pure seasonality (calendar-based), not price-based.
Now add a mean-reversion comparator that many quants try first:
- Long when the asset had a large negative short-horizon move (e.g., 5-day return below -2 standard deviations), then hold for 1–3 days.
The point isn’t to crown a winner; it’s to learn which one survives basic research hygiene.
Implementability constraints
To keep the test honest:
- Use only information available at decision time
- For calendar windows, that’s easy (you know the calendar).
- For mean reversion triggers, compute thresholds using trailing data only.
- Define execution explicitly
- You cannot “buy the close” unless you model a closing auction or use MOC orders.
- For a conservative baseline, trade at next open after a signal is known.
- Handle overlapping trades
- Turn-of-month windows overlap only at boundaries; mean reversion triggers can cluster.
- Decide: allow stacking positions (usually no), or take the most recent signal.
- Cost model Even for SPY, costs aren’t zero:
- Commission: likely 0.
- Spread + slippage: model as, say, 1–3 bps per side for SPY; more for smaller ETFs.
- For futures: include fees + bid/ask + impact proxy.
- Multiple testing discipline If you sweep 50 calendar windows and report the best one, you’re doing p-hacking. In this lab, pre-commit to a small set of windows.
Minimal pseudocode
Calendar strategy:
# precompute trading_days and month boundaries
for each day t:
if t is last_trading_day_of_month:
signal[t] = +1 # enter long next open
if t is 3rd_trading_day_of_month:
exit_signal[t] = 1 # exit next open
pos = 0
for each day t:
if signal[t-1] == +1:
pos = 1
if exit_signal[t-1] == 1:
pos = 0
strat_ret[t] = pos * r_open_to_open[t] - costs(turnover)
Mean-reversion comparator:
for each day t:
ret5 = P[t-1]/P[t-6]-1
sigma5 = stdev(rolling_5d_returns over past N days)
if ret5 < -2 * sigma5:
enter[t] = 1
pos = 0
hold = 0
for each day t:
if pos==0 and enter[t-1]==1:
pos=1; hold=3
if pos==1:
hold -= 1
if hold==0:
pos=0
strat_ret[t] = pos * r_open_to_open[t] - costs(turnover)
(Use open-to-open returns to match “trade at open” assumptions; you can swap to close-to-close if you can defend it.)
What to measure
1) Basic performance
- CAGR / annualized return
- Volatility
- Sharpe (but don’t stop there)
2) Concentration & dependence
Turn-of-month often earns its returns in a tiny fraction of days.
- % of total PnL contributed by the “best 10” turn-of-month windows.
- Worst year / best year.
3) Stability across subperiods
At minimum:
- 1993–2007 vs 2008–2019 vs 2020–present (or whatever your data allows).
- If it flips sign, treat it as a warning.
4) Risk alignment
Because the calendar strategy is “in the market” only ~4 days per month, it has lower beta.
- Compare against a risk-matched benchmark (e.g., buy-and-hold scaled to the same volatility).
- Report beta to the index.
5) Costs & capacity sensitivity
- Run costs at 0 / 2 / 5 / 10 bps per side.
- If the edge disappears at 5 bps, it’s not robust for most real trading.
What could break
- Calendar definitions across exchanges and datasets “Last trading day” depends on the trading calendar. Holidays matter. If your calendar is wrong, your signal is wrong.
- Execution fantasy at the close/open Turn-of-month rules are sensitive to which price you assume you get. If you compute signals using the close and also fill at the same close, you’re granting yourself free liquidity.
- Hidden factor exposure Turn-of-month can be repackaged beta (risk-on exposure). Check factor controls; if “alpha” vanishes, treat it as explained rather than discovered.
- Overfitting via window choice If you test 1-day, 2-day, …, 10-day windows and keep the best, you’ve effectively fit noise. Keep the rule simple and pre-registered.
- Regime shift / structural change If the effect is driven by a specific era (e.g., mutual-fund flow patterns), it can decay as the market structure changes.
Close
By the end of this mini-lab you should be able to say, in one sentence, which of these is true:
- “Turn-of-month is a small but persistent seasonal edge that survives costs,” or
- “It’s mostly a low-exposure beta profile plus measurement choices.”
Either outcome is useful—because the research habit you’re building is to separate a neat story from a tradable claim.