Classifying Bull and Bear markets with a two-state Markov chain
A two-state Markov chain in Python that classifies S&P 500 market conditions as Bull or Bear, built on 20-day moving averages of daily returns across 2,244 trading-day observations from 2015 to 2024. Transition probabilities, steady-state distributions, first-passage probabilities, and multistep transition matrices quantify regime persistence: a 93.6% chance of staying Bull, and a 68.3% long-run Bull-state probability.
- Python
- NumPy
- Pandas
- Markov Chains
- Statistics
2,244
Trading-day observations
S&P 500 daily returns, 2015 to 2024
93.6%
Bull-state persistence
Probability of remaining Bull
68.3%
Long-run Bull probability
Steady-state distribution
2
Regimes modeled
Bull vs Bear via 20-day moving average
DATA
2,244 S&P 500 trading days
SIGNAL
20-day MA of daily returns
STATES
Bull / Bear classification
P(Bull → Bull)
93.6%
Regime persistence
P(Bull → Bear)
6.4%
One-step flip chance
π Bull (steady state)
68.3%
Long-run Bull share
π Bear (steady state)
31.7%
Long-run Bear share
RESULT
The market stays Bull: 93.6% persistence, 68.3% long-run
Transition matrix, steady-state distribution, first-passage probabilities, and multistep matrices estimated in NumPy and Pandas.
P · π · first-passage · Pⁿ
BULL DOMINANT
Context
Markets move in regimes, not in independent rolls of the dice
Daily returns are famously hard to predict. But the condition the market is in — a multi-year climb or a sustained drawdown — tends to persist. That persistence is exactly what a Markov chain models: a system that jumps between a small number of states, where tomorrow's state depends only on today's, not on the full path that got us here.
This study turns ten years of S&P 500 data, 2,244 trading-day observations from 2015 through 2024, into a two-state chain: Bull or Bear. The classification signal is deliberately simple — the 20-day moving average of daily returns — so the interesting work lives in the estimation, not in feature engineering.
Method
From daily returns to an estimated transition matrix
Daily returns were computed from S&P 500 closing prices, smoothed with a 20-day moving average, and thresholded into two states. From the resulting regime sequence, the one-step transition matrix was estimated by maximum likelihood: count every Bull-to-Bull, Bull-to-Bear, Bear-to-Bull, and Bear-to-Bear transition, then normalize by the number of departures from each state.
With the transition matrix in hand, NumPy and Pandas carried the rest of the analysis: the steady-state distribution (the eigenvector of the matrix with eigenvalue 1), first-passage probabilities (the chance of hitting one state from the other for the first time), and multistep transition matrices Pⁿ that answer where the market is likely to be n days out from any starting state.
| Quantity | Value | Meaning |
|---|---|---|
| P(Bull → Bull) | 93.6% | Probability the Bull regime persists one more day |
| P(Bull → Bear) | 6.4% | One-day chance of a regime flip out of Bull |
| π Bull (steady state) | 68.3% | Long-run share of time spent in the Bull regime |
| π Bear (steady state) | 31.7% | Long-run share of time spent in the Bear regime |
Bull-to-Bear is the complement of Bull-to-Bull; steady-state shares sum to one.
Assumptions
Two states, one window, one simplifying property
Three modeling choices drive everything downstream, so they are worth stating explicitly. First, the Markov property: tomorrow's regime is treated as depending only on today's, not on the full path of recent days. That is a simplification — markets have memory — but it is the simplification that makes a transition matrix the right tool, and the estimated matrix can be checked against the data for plausibility.
Second, the regime definition: the sign of the 20-day moving average of daily returns. A shorter window reacts faster but flickers; a longer window (50 or 100 days) is smoother but lags regime changes. Twenty days was chosen as a defensible middle: responsive enough to catch the COVID-era swing, smooth enough to avoid daily noise. Third, two states rather than three (adding a flat/Sideways regime) — two states keep the matrix readable and the first-passage results interpretable, which mattered more here than extra granularity.
Alternatives considered and set aside: hidden Markov models with more states, which add parameters and estimation risk without data to justify them at this sample size; and price-level signals, which react more slowly than return-based moving averages. The chosen design optimizes for auditability: every number in the results section can be re-derived from the transition counts.
Findings
Regimes persist, and the Bull regime persists hardest
The dominant result is persistence. Once the market is classified as Bull, it stays Bull with probability 93.6% on the next day — the diagonal of the transition matrix is heavily loaded, which is the mathematical signature of a system that does not flip states casually. Bear regimes, while less frequent in the long run, are exactly where that persistence cuts both ways: entering a drawdown means expecting a run of Bear days, not a quick bounce.
The steady-state distribution puts numbers behind a fact every investor learns the hard way: over 2015 to 2024, the market spent roughly 68.3% of its time in the Bull regime and 31.7% in Bear. The first-passage and multistep results round out the picture — given enough days, the chain converges to that 68/32 split no matter which state it starts in, and the multistep matrices show the convergence path for any horizon n.
Outcome
A compact model that makes regime risk legible
The finished analysis is a Python pipeline in Pandas and NumPy that takes raw price data and returns the full Markov toolkit: the estimated transition matrix, steady-state distribution, first-passage probabilities, and multistep matrices. Every headline number — 93.6% Bull persistence, 68.3% long-run Bull share — falls out of that one matrix.
For an operations-minded view of markets, that compression is the point: two states, four transition probabilities, and a clear statement of how long each regime is likely to last. It is the same discipline as a time study on a factory floor — observe the system, count the transitions, and let the steady state speak.
Limitations
One decade, one definition, no trading claims
The chain is estimated from a single decade (2015–2024) that includes the COVID crash and recovery — an unusually violent episode that affects the transition counts. A different decade would produce a different matrix, and the steady state should be read as descriptive of this sample, not as a law of markets.
The regimes are defined by construction (the 20-day moving-average rule), so the model characterizes persistence of that definition; it does not discover regimes independently. And nothing here is a trading strategy: the analysis quantifies how long regimes tend to last, not what any asset will do next.
Lessons
Simple states, rigorous estimation
Constraining the model to two states forced clarity about what a “regime” actually is, and the 20-day moving-average threshold turned out to be a defensible, reproducible definition rather than a fitted one. The more valuable skill was the estimation work behind it: building the transition counts correctly, recovering the steady state from the matrix itself, and using first-passage and multistep results to check that the model behaved sensibly at every horizon.
It also reinforced a habit from the rest of my work: report the quantity that answers the actual question. Here, that means regime persistence and long-run occupancy, not a noisy day-ahead prediction no model can honestly claim.