← All Articles

Is there empirical evidence of a "Santa Claus Rally"?

Is there empirical evidence of a “Santa Claus Rally”?

A Warning About Market Truisms

Austin Starks

Austin Starks

6 min read

As an investor, I’m absolutely sick of market myths and unverified beliefs.

Other investors seem to be allergic to critical thinking and analysis. Myths such as “a stock having a low P/E ratio means it’s good” are pervasive in the industry, and newcomers who want to get started are deafened and defeated by all of the noise from people that don’t know better.

For example, if you’re an investor, you have probably heard of the “Santa Claus Rally”.

Investopedia defines it as “a sustained increase in the stock market that occurs around the Christmas holiday on Dec 25”.

The existence (or lack thereof) of this phenomenon is another example of stock market truism. While it “makes sense” that the market might go up for Christmas, is there any actual evidence of such a rally actually existing?

My job is to find out.

Performing quantitative analysis

To find out whether the Santa Claus rally is a real thing, I’m going to perform statistical analysis. Here’s exactly what I’m doing.

Gathering and Preparing the Data

To perform this analysis, we will do the following:

  1. Gather SPY daily adjusted-close data from January 1, 2000 through December 31, 2023, matching the printed SQL and Python year arrays.
  2. Separate the daily returns into two groups: holiday period and non-holiday period for each year.
  3. Compute the number of trading days, mean return, and standard deviation for both periods.

To gather this data, we can use an online platform like NexusTrade, to query and compute the data using natural language.

Using NexusTrade to fetch and compute the data

Comparative Analysis of Holiday vs Non-Holiday Stock Returns (2000-2023)

A detailed analysis comparing average daily returns, standard deviation, and risk-adjusted returns for the holiday…

nexustrade.io

NexusTrade is an AI-Powered financial analysis tool. Using its AI-Powered Stock Screener, we can fetch and compute all of the data needed to perform our analysis.

Behind the scenes, NexusTrade runs an advanced SQL query to perform the computation. If we wanted to be more confident in our results, we could analyze the SQL query to make sure its fetching the correct data.

WITH 
years AS (
SELECT year
FROM UNNEST(GENERATE_ARRAY(2000, 2023)) AS year
),
daily_returns AS (
SELECT
EXTRACT(YEAR FROM DATE(date)) AS year,
date,
adjustedClosingPrice,
LAG(adjustedClosingPrice) OVER (ORDER BY date) AS prev_price,
CASE
WHEN (EXTRACT(MONTH FROM date) = 12 AND EXTRACT(DAY FROM date) >= 25)
OR (EXTRACT(MONTH FROM date) = 1 AND EXTRACT(DAY FROM date) <= 2)
THEN TRUE
ELSE FALSE
END AS is_holiday_period,
SAFE_DIVIDE(
(adjustedClosingPrice - LAG(adjustedClosingPrice) OVER (ORDER BY date)),
LAG(adjustedClosingPrice) OVER (ORDER BY date)
) * 100 AS daily_return
FROM `nexustrade-io.universalstockfundamentals.price_data`
WHERE
symbol = 'SPY'
AND DATE(date) >= '2000-01-01'
AND DATE(date) <= '2023-12-31'
),
period_stats AS (
SELECT
year,
is_holiday_period,
COUNT(*) AS trading_days,
AVG(daily_return) AS avg_daily_return,
STDDEV(daily_return) AS stddev_daily_return,
SAFE_DIVIDE(
AVG(daily_return),
NULLIF(STDDEV(daily_return), 0)
) AS return_per_risk
FROM daily_returns
WHERE daily_return IS NOT NULL
GROUP BY year, is_holiday_period
)
SELECT
y.year,
MAX(CASE WHEN is_holiday_period THEN trading_days END) AS holiday_trading_days,
MAX(CASE WHEN NOT is_holiday_period THEN trading_days END) AS non_holiday_trading_days,
MAX(CASE WHEN is_holiday_period THEN avg_daily_return END) AS holiday_avg_return,
MAX(CASE WHEN NOT is_holiday_period THEN avg_daily_return END) AS non_holiday_avg_return,
MAX(CASE WHEN is_holiday_period THEN stddev_daily_return END) AS holiday_stddev,
MAX(CASE WHEN NOT is_holiday_period THEN stddev_daily_return END) AS non_holiday_stddev,
MAX(CASE WHEN is_holiday_period THEN return_per_risk END) AS holiday_return_per_risk,
MAX(CASE WHEN NOT is_holiday_period THEN return_per_risk END) AS non_holiday_return_per_risk
FROM
years y
LEFT JOIN
period_stats ps
ON
y.year = ps.year
GROUP BY
y.year
ORDER BY
y.year;

Once we have our data ready, we can continue our analysis by forming our hypothesis.

Our Initial Hypotheses

In order to determine whether there is evidence of a Christmas rally, we have to perform a statistical test.

In statistical testing, we have two hypothesis: the null hypothesis and the alternative hypothesis.

The null hypothesis is a statement asserting that there is no difference between variables, and any observed result is due to random chance. In this case, it would be the following:

The mean returns for the holiday period are equal to the mean returns for the non-holiday period

In contrast, the alternative hypothesis is the opposite. It is a statement that contradicts the null hypothesis, asserting that there is a difference between variables that is not due to random chance. In this case, the alternative hypothesis would be:

The mean returns for the holiday period are different from the mean returns for the non-holiday period.

In order to determine if our returns are different, we need to perform a statistical test.

Performing the Two-Sample T-Test

The printed analysis groups SPY observations by calendar year. Within each year, it labels January 1–2 and December 25–31 as holiday dates and the other dates as nonholiday. This combines the beginning and end of the same calendar year; it is not a contiguous December-to-next-January season. Only trading dates present in the data contribute.

A table with the mean return, standard deviation, and sample size during the holiday and non-holiday period

Steps:

  1. Unit of analysis: the Python uses 24 annual holiday means and 24 annual nonholiday means, one of each per calendar year from 2000 through 2023. The displayed day counts and within-year standard deviations are not used by this t-test.
  2. Printed test: scipy.stats.ttest_ind with equal_var=False compares those two arrays as independent samples. The same years supply both arrays, so this code does not model their pairing; a paired-year analysis would be a different test and could produce a different result.
  3. Assess Significance: Determine the p-value to assess whether observed differences are statistically significant at a chosen confidence level (e.g., 95%).

The original SQL and Python are retained below as the recorded analysis. I have not rerun or replaced them here. A corrected contiguous-season or paired-year test needs its own checked inputs and newly recorded output.

import pandas as pd
from scipy.stats import ttest_ind

# Data from NexusTrade
data = {
"year": list(range(2000, 2024)),
"holiday_avg_return": [0.0541, -0.4332, -0.0310, 0.9496, 0.0055, -0.4470, 0.1552, -0.5075, 0.6417, 0.4176,
0.0226, -0.1741, 0.0161, 0.7062, -0.4062, -0.1861, -0.2410, -0.0604, 1.4561, 0.0605,
0.4514, 0.1868, -0.0252, 0.0881],
"non_holiday_avg_return": [-0.0269, -0.0326, -0.0837, 0.0869, 0.0437, 0.0283, 0.0591, 0.0336, -0.1637, 0.1006,
0.0628, 0.0210, 0.0633, 0.1016, 0.0619, 0.0136, 0.0530, 0.0814, -0.0427, 0.1120,
0.0816, 0.1020, -0.0690, 0.0966],
"holiday_trading_days": [4, 5, 5, 5, 6, 4, 4, 4, 5, 5, 5, 4, 4, 5, 5, 5, 4, 4, 5, 5, 5, 5, 4, 4],
"non_holiday_trading_days": [247, 243, 247, 247, 246, 248, 247, 247, 248, 247, 247, 248, 246, 247, 247, 247, 248,
247, 246, 247, 248, 247, 247, 246]
}

# Convert data to a DataFrame
df = pd.DataFrame(data)

# Perform the two-sample t-test
holiday_returns = df["holiday_avg_return"]
non_holiday_returns = df["non_holiday_avg_return"]

t_stat, p_value = ttest_ind(holiday_returns, non_holiday_returns, equal_var=False)

# Display results
print(t_stat, p_value)

With this script, let’s analyze our results.

Interpreting the Results

The output of our two-sample t-test is as follows:

(0.8277042939072898, 0.41598212361269926)
  • T-Statistic: This value measures the size of the difference relative to the variation in your sample data. A higher absolute value indicates a greater difference between the groups.
  • P-Value: This indicates the probability of observing the results, or something more extreme, if the null hypothesis is true.

In our case:

  • P-Value (0.4160) > Significance Level (0.05): This means we fail to reject the null hypothesis.

What Does This Mean?

The printed independent-sample test of annual means reports p = 0.416, above 0.05, so it fails to reject equal means under that test’s assumptions. This is a bounded result for SPY and the printed calendar-year grouping. It does not establish that contiguous holiday seasons have no effect.

Failing to reject equal means is not proof of equality or absence of a rally. The grouping, use of annual means and unmodelled same-year pairing constrain what this result can answer.

This is extremely important because it highlights an important fact with investing – just because something seems true does not mean it is.

Discussion

This particular test did not establish a difference. A claim about contiguous December-to-January seasons needs a correctly labelled season identifier, defined treatment of incomplete endpoint seasons and a separately recorded analysis.

The perceived increase in market returns during this period can easily just be due to chance or other factors. Investors should be wary of buying stocks just because they think that stocks are supposed to go up in December.

This leads to the main point of this article – in investing, don’t believe everything you read online.

The printed test found little evidence for a difference in this SPY calendar-group sample under its stated annual-mean comparison. That bounded result does not answer every definition of a Christmas trading-season rally. Check the contiguous-season dates and the test’s unit of observation before applying it to that different question.

This article also shows the power of using objective data for stock market analysis. By using NexusTrade, we can gather objective data in order to better inform out stock trading decisions.

I hope that this article has taught you something — if you hear advice and it seems sound, it’s all over the internet, and has “reasoning” for being true, it doesn’t mean that it actually is. You should always conduct your own research when making financial decisions.

NexusTrade AI Chat — Talk with Aurora

Talk to an AI assistant to perform financial analysis and create algorithmic trading strategies.

nexustrade.io

Follow me: LinkedIn | X (Twitter) | TikTok | Instagram | Newsletter

Listen to me: Spotify | Amazon Music |

Put your research to work

Create a free account to research a company, build a strategy with Aurora, or inspect a historical backtest. Choose the task you want to try.

or

Free to browse. No credit card required.

Discussion

Sign in or create a free account to join the discussion.

No comments yet.