TL;DR

Crypto seasonality splits cleanly into two categories. Activity seasonality — volume, volatility, and spreads cycling with the waking hours of US, European, and Asian traders, dipping on weekends — is real, robust across studies, and genuinely modelable. Return seasonality — "Mondays are bullish," "October is Bitcoin's best month," the four-year halving cycle — is sample-dependent: documented in some windows, gone in others, and weaker as the market institutionalizes. Model the first with Fourier terms, STL, or Prophet and use it for execution timing and volatility forecasting. Treat the second as a hypothesis to test (code below), not an edge to trade.

Search for "bitcoin seasonality" and you get two genres of answer that flatly contradict each other. Trading blogs publish heatmaps of monthly returns and declare October bullish; academic papers run the formal tests and mostly fail to find stable calendar effects in returns. Both are looking at the same data. This article explains why they disagree, what the peer-reviewed evidence actually supports, and — since this is a forecasting site — exactly how to test for and model seasonal structure in crypto series with pandas and statsmodels.

What "Seasonality" Means in a Market That Never Closes

In equities, calendar effects piggyback on market structure: the exchange closes overnight and on weekends, options expire on the third Friday, funds rebalance at quarter-end. Crypto trades continuously, so any seasonality has to come from somewhere else. There are three distinct sources, and conflating them is the most common analytical mistake:

  • Human clocks. The market is open 24/7 but traders are not. Liquidity follows the sun: US and European business hours dominate volume, weekends are thin. This produces genuine periodic structure at 24-hour and 168-hour cycles.
  • Calendar conventions. Month-end, quarter-end, tax deadlines, "sell in May" analogs imported from equity folklore. These are hypotheses about return predictability, and they need formal testing.
  • Mechanical event cycles. Perpetual-futures funding every 8 hours, monthly options expiries, the quadrennial halving. These are real, scheduled events — but they are event effects, not seasonality in the statistical sense, and they need event-study methods rather than seasonal decomposition.

Keep this taxonomy in mind: the evidence is strong for the first category, weak for the second, and mixed-but-mechanical for the third.

What the Research Actually Finds

Hour-of-day: the most robust pattern in crypto

The largest study of Bitcoin calendar effects — Baur, Cahill, Godfrey, and Liu, using more than 15 million price and volume observations across seven exchanges — found a sharp asymmetry: return effects were time-varying with no persistent pattern, but trading-activity effects were persistent across every exchange, with lower activity during local evening hours and on weekends. That single result is a good one-sentence summary of the whole literature: activity is seasonal, returns mostly are not.

Where does activity concentrate? Research on intraday dynamics finds that most major cryptocurrencies post their highest hourly volumes during the overlap of London and New York equity hours (roughly 14:00–16:00 UTC) — crypto volume and volatility track traditional-market participation even though no exchange bell rings.

Return effects at specific hours have been documented, but read them carefully. Quantpedia's analysis of hourly Gemini data (October 2015 – February 2022) found significantly elevated returns at 22:00–23:00 UTC, when major Western markets are closed, and backtested a "buy at 21:00, sell at 23:00" rule at roughly 37% annualized with an 18.9% max drawdown. The caveats are the interesting part: that figure is gross of costs, and a strategy doing a round trip every single day needs its average per-trade edge to clear two taker fees plus spread — a high bar for a pattern measured in basis points. It is a finding about market microstructure, not free money.

Day-of-week: the contested middle ground

This is where blogs and journals diverge most. The early academic literature found something: Caporale and Plastun reported that Bitcoin returns on Mondays were significantly higher than on other days — while Litecoin, Ripple, and Dash showed no anomaly at all — and, crucially, their own trading simulations found the resulting profits mostly not significantly different from random. Aharon and Qadan independently documented higher Monday returns and volatility over a similar period.

Then the effect faded. Kaiser, testing ten major cryptocurrencies for the standard equity calendar anomalies, found no consistent, robust calendar effects in returns — but clear, robust patterns in activity: volume, volatility, and spread estimates are on average lower in January, on weekends, and during summer. A 2014–2024 study of Bitcoin's weekend effect reached the same split verdict over a full decade: no detectable weekend–weekday gap in average returns, but reliably lower volatility and volume on weekends. And Mueller's 2024 follow-up in Finance Research Letters found that the seasonal effects documented in the early literature have diminished as the market matured and institutional participation grew.

The honest synthesis: a Monday/weekend return effect existed in early-sample Bitcoin data, was never strong enough to trade reliably after costs, and largely disappeared from later samples. The weekend activity dip, by contrast, shows up in every study that looks for it.

Month-of-year: mostly folklore

Monthly return patterns are where overfitting risk is most acute. Bitcoin has traded liquidly since roughly 2013, which means any month-of-year claim rests on about a dozen observations per month — and those observations are dominated by where each month happened to fall in two or three boom-bust cycles. Studies that formally test month-of-year and Halloween-type effects across cryptocurrencies find them unstable across coins and subperiods. The only monthly regularity with multi-study support is, again, about activity: Kaiser's finding that trading volume and volatility drop in January and over the summer. A monthly-returns heatmap is a description of one path of history, not a seasonal model.

The Evidence Scoreboard

Claimed patternWhat the evidence saysRobust?
Intraday volume/volatility cycle (follows US/EU/Asia waking hours)Confirmed in essentially every study; persistent across exchanges and yearsYes
Weekend activity dip (volume, volatility, spreads)Confirmed across studies and a 10-year sampleYes
Hour-of-day return effects (e.g., 22:00–23:00 UTC)Documented in specific samples; thin after costs; stability unprovenPartial
Monday / day-of-week return effectPresent in early Bitcoin samples, faded in later ones; never robustly tradableFading
Month-of-year returns ("sell in May", "Uptober")Unstable across coins and subperiods; ~12 observations per monthNo
8-hour funding cycle effects on perpsMechanically real; microstructure effects around timestamps; arbitragedMechanical
Options-expiry "max pain" pullPopular narrative; evidence debated; volatility compression after expiry is the clearer effectDebated
Four-year halving cycle in returnsFour events total; the pattern visibly deviated after the 2024 halvingUntestable

Mechanical Cycles That Masquerade as Seasonality

Three scheduled event cycles show up in naive seasonal decompositions of crypto data, and you should model them as events, not seasons.

The 8-hour funding cycle

Perpetual futures — the dominant crypto derivative — keep their price tethered to spot via funding payments exchanged between longs and shorts, settled on most major venues every 8 hours (00:00, 08:00, 16:00 UTC). Traders sometimes flatten positions just before the timestamp to avoid paying funding, which leaves footprints in spreads, depth, and short-horizon flows around those hours. If you run an hourly seasonality study on perp data without dummying out funding hours, you will "discover" a spurious 8-hour seasonal that is really a scheduled cash flow.

Options expiry

Crypto options concentrate on monthly and quarterly expiries (08:00 UTC on Deribit), and the notional involved is now large — the December 2025 year-end expiry alone covered roughly $27 billion in BTC and ETH options. The popular "max pain" theory — spot gravitating toward the strike that inflicts maximum loss on option buyers — remains contested; the better-evidenced regularity is that implied volatility tends to compress once a large expiry resolves the uncertainty. Either way, expiry effects cluster on specific dates, which is event structure, not seasonality.

The halving "cycle"

Bitcoin's block subsidy halves roughly every four years — November 2012, July 2016, May 2020, April 2024. Three post-halving years in a row produced new all-time highs, and a generation of traders extracted a "four-year cycle" from it. Statistically this was always untestable: four events is not a sample. And the pattern broke on schedule — analysts now argue the four-year cycle died after the 2024 halving, as Bitcoin's first negative post-halving year coincided with ETF flows that dwarf the supply impact of newly mined coins. The halving is a real supply event; the cycle built on it was a narrative fitted to three observations.

Testing for Day-of-Week Effects Yourself (Python)

Before modeling anything, run the test. The standard approach is a dummy-variable regression of log returns on day-of-week indicators — but three pitfalls invalidate most casual versions of this analysis:

  • Volatility clustering. Crypto returns are heteroskedastic and autocorrelated in squares; ordinary OLS standard errors overstate significance. Use HAC (Newey–West) errors at minimum, or a GARCH specification as the academic papers do.
  • Multiple comparisons. Seven days, dozens of coins, several subperiods — test enough combinations and some will clear p < 0.05 by chance. Apply a Bonferroni or FDR correction to the family of tests you actually ran. Our article on how many trades make a significant test covers the same logic from the strategy side.
  • Subsample instability. A coefficient driven entirely by 2017 is a historical anecdote, not a seasonal effect. Re-estimate over rolling or split windows and require the sign to survive.
import numpy as np import pandas as pd import statsmodels.formula.api as smf from scipy import stats # daily OHLCV from any source (exchange API export, CSV) px = pd.read_csv("btc_daily.csv", parse_dates=["date"], index_col="date") ret = np.log(px["close"]).diff().dropna().to_frame("ret") ret["dow"] = ret.index.day_name() # 1) Dummy regression, Monday baseline, Newey-West (HAC) errors res = smf.ols("ret ~ C(dow, Treatment('Monday'))", data=ret).fit( cov_type="HAC", cov_kwds={"maxlags": 7}) print(res.summary()) # 2) Non-parametric sanity check: do the 7 distributions differ at all? groups = [g["ret"].values for _, g in ret.groupby("dow")] h, p = stats.kruskal(*groups) print(f"Kruskal-Wallis p = {p:.4f}") # 3) Bonferroni across the 6 day dummies, then check subsample stability alpha = 0.05 / 6 for window, sub in ret.groupby(pd.Grouper(freq="2YS")): if len(sub) < 400: continue r = smf.ols("ret ~ C(dow, Treatment('Monday'))", data=sub).fit( cov_type="HAC", cov_kwds={"maxlags": 7}) n_sig = int((r.pvalues.iloc[1:] < alpha).sum()) print(window.year, "significant day dummies:", n_sig)

Interpretation rules of thumb: if the Kruskal–Wallis test on the full sample is not significant, stop — there is no day-of-week structure worth modeling in returns. If individual dummies are significant in the full sample but flip sign or vanish across the two-year windows, you have found the same thing the literature found: a transient artifact, not a stable season. Run the identical script on volume or squared returns and you will see the contrast immediately — the activity seasonality is so strong it survives any correction you throw at it.

One more discipline note: decide the test set before you peek. The same data-snooping mechanics that break backtests break seasonality studies, and crypto's short history (one or two genuinely independent market regimes) makes it worse than in equities.

Putting Seasonality into a Forecasting Model

When the target is volume, realized volatility, or spreads — where the seasonality is real — you have four standard tools, in increasing order of machinery.

1. Calendar dummies

For coarse cycles (day-of-week on daily data) plain one-hot dummies are unbeatable: 6 parameters, fully interpretable, works in any regression or gradient-boosted model. Tree ensembles handle the integer dayofweek directly; for neural nets, prefer the cyclical encoding below so Sunday and Monday are neighbors in feature space.

2. Fourier terms

For smooth high-resolution cycles (hour-of-day on hourly data) dummies cost 23 parameters and ignore smoothness. A truncated Fourier basis captures the same shape in a handful of terms:

def fourier_features(index: pd.DatetimeIndex, period: float, order: int) -> pd.DataFrame: """Sin/cos pairs for a cycle of `period` steps (24=daily, 168=weekly on hourly data).""" t = np.arange(len(index)) feats = {} for k in range(1, order + 1): feats[f"sin_p{period}_k{k}"] = np.sin(2 * np.pi * k * t / period) feats[f"cos_p{period}_k{k}"] = np.cos(2 * np.pi * k * t / period) return pd.DataFrame(feats, index=index) # hourly realized-vol model: daily + weekly cycles as exogenous regressors X = pd.concat([fourier_features(rv.index, 24, order=3), fourier_features(rv.index, 168, order=2)], axis=1) import statsmodels.api as sm model = sm.OLS(np.log(rv), sm.add_constant(X)).fit(cov_type="HAC", cov_kwds={"maxlags": 24})

The same matrix drops into SARIMAX as exog, into LightGBM as features, or into an LSTM input stack. Start with order 2–3 and increase only if residual diagnostics show leftover periodicity — high Fourier orders are an easy way to overfit the exact wiggle of your training sample.

3. STL decomposition for diagnosis

Before committing to a seasonal structure, measure how much of the variance it actually explains. STL plus the seasonal-strength statistic from Hyndman and Athanasopoulos's Forecasting: Principles and Practice gives a number:

from statsmodels.tsa.seasonal import STL stl = STL(np.log(hourly["volume"]), period=168, robust=True).fit() strength = max(0, 1 - stl.resid.var() / (stl.resid + stl.seasonal).var()) print(f"weekly seasonal strength: {strength:.2f}") # ~0 = none, ~1 = dominant

Run this on log volume and you will get a high number; run it on returns and you will get approximately zero. That two-line experiment is the whole thesis of this article in code form.

4. Prophet for multi-seasonal series

Prophet models trend plus multiple Fourier-based seasonalities out of the box, which makes it convenient for crypto activity series with simultaneous daily and weekly cycles (see Prophet's seasonality documentation for the knobs):

from prophet import Prophet df = (np.log(hourly[["volume"]]) .reset_index() .rename(columns={"timestamp": "ds", "volume": "y"})) m = Prophet( daily_seasonality=10, # Fourier order for the 24h cycle weekly_seasonality=5, yearly_seasonality=False, # too few independent yearly cycles to trust ) m.fit(df) m.plot_components(m.predict(m.make_future_dataframe(periods=168, freq="h")))

Two warnings. First, point Prophet at volume or realized volatility, not at price — its piecewise-linear trend extrapolation is exactly the wrong prior for a martingale-like price series. Second, disable yearly seasonality for crypto: with under fifteen yearly cycles of liquid history, the yearly component mostly memorizes bull and bear runs. For a broader comparison of Prophet against ARIMA and neural approaches on financial data, see our ARIMA vs Prophet vs LSTM vs N-BEATS comparison.

Whatever the model, validate it with walk-forward splits rather than random cross-validation — seasonal features are notorious for leaking regime information when shuffled. Our guides to walk-forward analysis and train/validation/test splits for non-stationary series cover the mechanics.

Why Published Patterns Decay

Suppose you do find a return seasonal that passes every test above. The base rate says it will shrink. McLean and Pontiff, tracking 97 published return predictors in equities, found returns 26% lower out-of-sample and 58% lower post-publication — investors read the papers and arbitrage the edge away. Crypto should decay faster: there are no short-sale constraints on major venues, no market closes to delay the arbitrage, and the marginal participant is increasingly a quant fund rather than a hobbyist. That is precisely the pattern the literature shows — early-sample day-of-week effects (Caporale–Plastun, Aharon–Qadan) that later samples no longer reproduce, and a halving cycle that broke the moment ETF flows changed who the marginal buyer was.

The activity seasonality survives for the opposite reason: nobody can arbitrage away the fact that humans sleep. Patterns rooted in physical constraints persist; patterns rooted in mispricing get competed away. When evaluating any crypto seasonal claim, ask which kind it is — and remember that seasonal patterns can also be regime-dependent, strengthening or reversing between bull and bear markets, which is one reason regime-switching models pair naturally with seasonal features.

What Crypto Seasonality Is Actually Good For

The honest conclusion is not "seasonality is a myth." It is that the modelable part is not where most people look. Concretely:

  • Execution scheduling. The intraday volume curve is stable enough to build VWAP-style schedules around: concentrate child orders in the high-liquidity US/EU overlap, widen limit prices or pause during the thin 00:00–06:00 UTC stretch and weekends. This is the highest-value use of crypto seasonality, and it requires no return prediction at all. Pair it with realistic fee assumptions — see our crypto transaction-cost analysis.
  • Volatility forecasting. Hour-of-day and day-of-week Fourier terms are cheap, robust features for realized-vol models, and the improvement shows up consistently because the underlying pattern does.
  • Market-making and risk limits. Spreads and depth follow the same clock; quoting and inventory limits should too. Weekend risk deserves explicit treatment — thinner books mean larger gaps for the same news.
  • Event hygiene in research. Dummy out funding timestamps and option expiries before testing anything else on hourly perp data, or your "seasonality" will be a settlement schedule.
  • Return prediction. Treat any return seasonal as guilty until proven innocent: HAC errors, multiple-testing correction, subsample stability, costs, and a pre-registered out-of-sample window. If it survives all five, size it as one weak signal among many — never as a standalone strategy.

Bottom Line

Is seasonality in crypto markets myth or modelable pattern? Both, depending on the variable. Returns: mostly myth — early calendar anomalies were real but small, untradable after costs, and have faded as the market matured. Activity: thoroughly modelable — volume, volatility, and liquidity cycle with human waking hours so reliably that the pattern survives every robustness check researchers have applied. Build your forecasting features on the second, test the first with the statistical discipline it rarely receives, and treat funding windows, expiries, and halvings as scheduled events rather than seasons.

Related reading: Comparing ARIMA, Prophet, LSTM and N-BEATSRegime-Switching Models with Hidden Markov ChainsStationarity Testing: KPSS vs ADF vs Phillips-Perron