Quant BuffetRelax, Not Over Thinking

Global Equity Rotation Strategy Based on Seasonal Market Timing

Log in to collect

Academic paper

The Optimism Cycle: Sell in May

AuthorsRonald Q. Doeswijk; research enterprise of Rabobank and Robeco; the Netherlands

Institute
  • ?Independent

Strategy in a nutshell

Hold global equities from November to April, then transition to cash from May to October. Alternatively, adopt a long position in stocks from northern hemisphere countries in winter and southern hemisphere countries in summer. Alternatively, invest in cyclical companies in winter and short defensive stocks, switching positions in summer.

Economic rationale

Value and momentum strategies, as previously noted, have two possible explanations. Firstly, Kamstra, Kramer, and Levi (2003) attribute seasonal patterns to the Seasonal Affective Disorder (SAD) effect, linking shorter days to winter depression and heightened risk aversion. They suggest that as days shorten, depression increases, leading to decreased risk appetite. This link between day length, depression, and risk aversion influences stock market returns, termed the SAD effect. Another explanation is the optimism cycle, where year-end optimism transitions to economic reality, resulting in a summer stock market lull. Psychological factors drive seasonal variations, suggesting investors overweight equities Nov-Apr and underweight May-Oct.

Backtest performance

Annualised return8.80%
Volatility33.10%
Beta0.501
Sharpe ratio0.21
Sortino ratio0.15
Maximum drawdown- 36.6%
Win rate79%

Full Python code

from AlgoLib import *  # Imports all classes, functions, and variables defined in the AlgoLib library, making them available for use in this script.

class SeasonalityInEquitiesAlgorithm(XXX):  # Defines a new class named SeasonalityInEquitiesAlgorithm, which is intended to inherit from a class represented by XXX (you'll need to replace XXX with the actual base class name from AlgoLib).

def Initialize(self):  # Defines the Initialize method, which is called when the algorithm starts to set up initial configuration like start date, initial cash, and subscribed data.
self.SetStartDate(1999, 1, 1)  # Sets the start date of the backtest to January 1, 1999.
self.SetCash(100000)  # Sets the initial cash for the algorithm to $100,000.

self.AddEquity("SPY", Resolution.Daily)  # Subscribes to daily resolution data for the SPY ETF, allowing the algorithm to receive data and make trades based on it.
self.AddEquity("SHY", Resolution.Daily)  # Subscribes to daily resolution data for the SHY ETF, similar to SPY.

self.Schedule.On(self.DateRules.MonthStart("SPY"), 
self.TimeRules.AfterMarketOpen("SPY"), self.Rebalance)  # Schedules the Rebalance method to run at the market open on the first trading day of each month for the SPY ETF.

def Rebalance(self):  # Defines the Rebalance method, which contains the logic to be executed during the scheduled rebalance.
if self.Time.month == 5:  # Checks if the current month is May.
    self.Liquidate("SPY")  # If it is May, liquidates all holdings in SPY ETF to move to cash.
if self.Time.month == 11:  # Checks if the current month is November.
    self.SetHoldings("SPY", 1)  # If it is November, invests 100% of the portfolio into the SPY ETF.