Remember that old Wall Street chestnut, "Sell in May and go away"? Well, grab your favorite beverage and settle in, because we're about to dive into this age-old wisdom and see if it really holds water.
Now, I don't know about you, but I've always been a bit skeptical of these catchy market phrases. They sound great at cocktail parties, but do they actually work? That's exactly what I set out to discover.
In this article, we're going to break down our Market Seasonality Study step by step.
Below is a graph of the market with a "buy" at the start of the strong period and a "sell" at the end of the strong period.
Testing the "Buy in November, Sell in May" Strategy
To evaluate the popular trading concept of buying the S&P in November and selling in May, I set up a test with the following parameters:
- Market: S&P cash market
- Time period: 1960 to present
- Position sizing: Risk-adjusted, with $5,000 risked per trade based on market volatility
- Transaction costs: Not included (no slippage or commissions accounted for)
The core logic of this strategy can be implemented in EasyLanguage as follows:
CurrentMonth = Month(Date);
If (CurrentMonth = BuyMonth) And (MP = 0) Then
Buy("Buy Month") iShares contracts next bar at market;
If (CurrentMonth = SellMonth) Then
Sell("Sell Month") iShares contracts next bar at market;
This code does the following:
- Determines the current month
- If it's the buy month (November) and we're not in the market, it enters a long position
- If it's the sell month (May), it exits the position
By using this simple logic, we can test whether this well-known market adage holds up over a long period of historical data.
Test Parameters and Assumptions
I decided to test the strategy on the S&P cash index, with data going back to 1960. The following assumptions were made for this test:
- Starting account size: $100,000
- Test period: January 1960 through May 2024
- Position sizing: Full account size used when opening a new position
- Equity management: P&L not accumulated to the starting equity
- Transaction costs: No deductions for commissions and slippage
- Risk management: No stops were used
With these parameters set, we can now input the key months for our seasonality strategy:
- Buy month: November
- Sell month: May
Using these inputs, we generated the following equity graph:
"Sell in May and Go Away" Strategy Results
The equity curve we generated visually represents the performance of our "Sell in May and Go Away" strategy over the 64-year test period. It allows us to see the long-term trend as well as any significant drawdowns or periods of exceptional growth. And I must say, it sure looks like these months have a long bias - those are some impressive results!
Let's break down the numbers:
- Total Profit: $4,640,085
- Max Intra-day Drawdown: $1,403,538
- Net Profit vs Drawdown Ratio: 3.3
In simpler terms, for every dollar of drawdown, the strategy is making just over three dollars in profit. That's a respectable ratio by most trading standards.
Inverting the Strategy
But here's where it gets really interesting. What would happen if we flipped our strategy on its head? Instead of buying in November and selling in May, what if we did the opposite - buying in May and selling in November?
To find out, I inverted the BuyMonth and SellMonth inputs in our test. Here's the resulting equity curve:
Analyzing the Inverted Strategy Results
The inverted equity curve provides a fascinating contrast to our original strategy, allowing us to visually compare the performance of buying during the traditionally "weak" months versus the "strong" months.
Let's break down the performance of this inverted strategy:
- 1960-1970: The equity curve consistently declined.
- 1970-1978: It bottomed out and began to climb.
- 1978-1997: Steady growth, reaching an equity peak in 1997.
- 1997-2008: Entered a drawdown period, bottoming in 2008.
- 2008-2021: Recovered, reaching new equity highs in 2020 and 2021.
Key metrics for the inverted strategy:
- Total Profit: $94,148
- Max Intra-day Drawdown: $92,357
- Net Profit vs Drawdown Ratio: 1.0
This 1:1 ratio indicates that you must endure a dollar of drawdown for every dollar of profit - a much less attractive risk-reward proposition compared to our original strategy.
Let's focus on the strong season period from November-May moving forward. Can we add a filter to improve the results?
Implementing a Simple Moving Average Filter
To refine our strategy and avoid potentially unfavorable entry and exit points, we're introducing a 30-period simple moving average (SMA) as a short-term trend filter. This addition aims to prevent us from:
- Buying immediately into a falling market
- Selling immediately into a rising market
Here's how it works:
- For Selling: If May (our SellMonth) arrives and the market is rising (price above the 30-period SMA), we delay selling until the price closes below the SMA.
- For Buying: If November (our BuyMonth) arrives, we only buy when the price closes above the SMA.
To implement this in EasyLanguage, we create two flags: BuyFlag and SellFlag. These indicate when the proper conditions for buying or selling are met based on our short-term trend filter.
if (MinorTrendLen > 0) Then
BuyFlag = Close > Average(Close, MinorTrendLen)
Else
BuyFlag = true;
If (MinorTrendLen > 0) Then
SellFlag = Close < Average(Close, MinorTrendLen)
Else
SellFlag = true;
The MinorTrendLen variable is an input that determines the SMA's look-back period. An additional check allows us to enable or disable the SMA filter:
- If MinorTrendLen > 0: The SMA filter is active
- If MinorTrendLen = 0: Both flags are always true, effectively disabling the filter
This flexibility lets us easily compare performance with and without the filter.
Strong Seasonality Trade (November-May) With Filters
Baseline | SMA Filter | |
---|---|---|
Net Profit | $4,640,095 | $5,961,005 |
Profit Factor | 4.42 | 4.81 |
Total Trades | 64 | 64 |
Avg.Trade Net Profit | $72,501 | $93,140 |
Annual Rate of Return | 9.54% | 9.93% |
Max Drawdown(Intraday) | $1,403,538 | $1,856,564 |
NP vs Drawdown | 3.3 | 3.2 |
We increased the net profit, profit factor, average profit per trade, and annual rate of return. There is a slight decline in the NP vs Drawdown ratio, but it's tiny. We can decently pull more profit by applying a simple moving average.
MACD Filter
A standard MACD filter is a well known indicator that may help with timing. I'm going to add a MACD calculation, using the default settings, and only open a new trade when the MACD line is above zero. Likewise, I'm only going to sell when the MACD line is below zero. Within EasyLanguage we can create a MACD filter by creating two Boolean flags called MACDBull and MACDBear which will indicate when the proper major market trend is in our favor.
If ( MACD_Filter ) Then
Begin
MyMACD = MACD( Close, FastLength, SlowLength );
MACDAvg = XAverage( MyMACD, MACDLength );
MACDDiff = MyMACD - MACDAvg;
If ( MyMACD crosses over 0 ) Then
Begin
MACDBull = True;
MACDBear = False;
End
Else If ( MyMACD crosses under 0 ) Then
Begin
MACDBull = False;
MACDBear = True;
End;
End
Else Begin
MACDBull = True;
MACDBear = True;
End;
Below are the results with the MACD filter:
Strong Seasonality Trade (November-May) With Filters
Baseline | SMA Filter | MACD Filter | |
---|---|---|---|
Net Profit | $4,640,095 | $5,961,005 | $4,685,543 |
Profit Factor | 4.42 | 4.81 | 5.35 |
Total Trades | 64 | 64 | 63 |
Avg.Trade Net Profit | $72,501 | $93,140 | $74,373 |
Annual Rate of Return | 9.54% | 9.93% | 9.55% |
Max Drawdown (Intraday) | $1,403,538 | $1,856,564 | $1,205,264 |
NP vs Drawdown | 3.3 | 3.2 | 3.8 |
Utilizing the MACD filter and comparing it to our baseline system, we can see we don't make as much more as the simple moving average filter, however, we increased our risk adjusted return with a NP vs DD of 3.8. So, if drawdown is your concern and not just pure profit it looks the MACD filter is slightly better.
RSI Filter
For our final filter I will try the RSI indicator with its default loopback period of 14. Again, like the MACD calculation, I want price moving in our direction so I want the RSI calculation to be above zero when opening a position and below zero when closing a position.
If ( RSI_Filter ) Then
Begin
RSIBull = RSI(Close, 14 ) > 50;
RSIBear = RSI(Close, 14 ) < 50;
End
Else Begin
RSIBull = true;
RSIBear = true;
End;
Strong Seasonality Trade (November-May) With Filters
Baseline | SMA Filter | MACD Filter | RSI Filter | |
---|---|---|---|---|
Net Profit | $4,640,095 | $5,961,005 | $4,685,543 | $4,080,657 |
Profit Factor | 4.42 | 4.81 | 5.35 | 4.24 |
Total Trades | 64 | 64 | 63 | 64 |
Avg.Trade Net Profit | $72,501 | $93,140 | $74,373 | $63,760 |
Annual Rate of Return | 9.54% | 9.93% | 9.55% | 9.34% |
Max Drawdown (Intraday) | $1,403,538 | $1,856,564 | $1,205,264 | $1,291,784 |
NP vs Drawdown | 3.3 | 3.2 | 3.8 | 3.1 |
Filter Comparison Results
The RSI filter performed worse than both the MACD and SMA filters.
In the end, it appears that applying either an SMA filter or an MACD filter can improve the baseline results. Both filters are relatively simple to implement and were tested for this article using their default values. Of course, this simple study could be expanded much further.
Applying Filters to the Weak Seasonality Period
After performing the different filter tests and selecting the simple moving average filter as the most effective, I began to wonder how our three filters would perform if applied to the weak seasonality period. Below are the performance results.
Weak Seasonality Trade (May-November) With Filters
No Filter | SMA Filter | MACD Filter | RSI Filter | |
---|---|---|---|---|
Net Profit | $94,148 | $244,406 | $221,672 | $121,740 |
Profit Factor | 1.42 | 1.67 | 1.79 | 1.52 |
Total Trades | 64 | 64 | 63 | 64 |
Avg.Trade Net Profit | $1,471 | $3,818 | $3,518 | $1,902 |
Annual Rate of Return | 3.64% | 5.03% | 4.88% | 4.00% |
Max Drawdown (Intraday) | $92,357 | $128,921 | $106,121 | $100,544 |
NP vs Drawdown | 1.0 | 1.7 | 2.0 | 1.2 |
We can see that adding MACD Filter produces the best results in terms risk adjusted return (NP vs Drawdown). The SMA Filter products the best results in terms of net profit. Both provide a radical change when compared to the No Filter situation.
Conclusion
It certainly appears there is a significant seasonal edge in the S&P market. The trading rules we used above for the S&P cash market could be applied to the SPY and DIA ETF markets. I've tested these ETFs, and they produce very similar results. The S&P futures market also yields comparable outcomes. Interestingly, this approach even seems to work well for some individual stocks.
Keep in mind that this market study did not utilize any market stops. This is not a complete trading system!
Practical Use: Market Regime Filter For Stock Index Markets
With some additional work, an automated trading system could be built from this study. Another application would be to use this study as a filter for other trading systems. I envision using these results as a regime filter for your existing trading systems that trade the stock index markets.
Strong Season Bull/Bear Filter
- Bull Market = if price is above 30-day SMA
- Bear Market = if price is at or below 30-day SMA
Weak Season Bull/Bear Filter
- Bull Market = if MACD is above zero
- Bear Market = if MACD is at or below zero
This seasonality filter could be applied to both automated trading systems and discretionary trading. While it may not be particularly helpful for intraday trading, it's worth testing in that context as well.
Being aware of these major market cycles can be invaluable in understanding current market conditions and potential future directions. This knowledge can enhance your overall market perspective and potentially improve your trading decisions.
I hope you found this study helpful and that it provides you with new insights for your trading strategies.
Jeff,
Thanks for the post. Curious how this strategy would compare to buy-and-hold?
I show 55.61 on Jan 1960 and 5,648.40 the Aug 2024 closing price of $SPX.X.
At 55.61, $100,000 would be able to buy 1,798.24 shs. At the current price of 5,648.40, the 1,798.24 shs. would be worth $10,157,166 – a bit more than the $5.961 million from the strategy. What am I missing?
What you’re missing in your assessment is the drawdown. First, calculate the drawdown you would experience with a buy-and-hold strategy. Then, calculate the Net Profit vs. Drawdown ratio and compare that to the strategy. With this strategy, you won’t endure severe drawdowns and will have a mechanical method for re-entering the market. Most people tend to sell during a drawdown and never re-enter. This strategy offers the advantage of managing drawdowns, making it easier to stay in the market compared to holding, which is difficult for most people to maintain.