Mean Reversion vs Seasonality — Is the Turn-of-Month Effect Real After Costs?

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:

  1. 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.
  1. 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.
  1. 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.
  1. 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.
  1. 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

  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. 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.