Identifying which of several distinct market states (bull, bear, volatile, sideways) the market or a stock currently occupies, to adapt strategy parameters accordingly.
In Plain English
Markets do not behave the same way all the time. A stock that predictably drifts upward during calm periods can become whipsaw and mean-reverting during volatile, fear-driven markets. A momentum strategy that generates strong returns in trending markets can produce devastating losses when trends reverse abruptly. Regime detection is the discipline of identifying which "mode" the market is currently in, so you can adapt accordingly.
The analogy is weather forecasting. You don't dress the same way in winter as in summer, even if the average annual temperature is mild. Strategies should not behave identically in a low-volatility bull market as they do in a high-volatility bear market — yet that's exactly what happens if you ignore regimes.
Most regime models divide market states into two to five categories. A simple two-regime model might distinguish "low volatility / trending up" from "high volatility / trending down." A more nuanced model might use four regimes: bull (uptrending, low volatility), bear (downtrending, elevated volatility), volatile (high volatility, no clear trend), and sideways (low volatility, no clear trend).
The practical payoff is enormous. Research consistently shows that momentum strategies have positive expected returns in bull and sideways regimes, but suffer sharp reversals at the onset of volatile or bear regimes. By detecting regime shifts early and reducing momentum exposure before the worst drawdowns, you can substantially improve the risk-adjusted returns of trend-following strategies.
Technical Definition
The Hidden Markov Model (HMM) is the classical approach to regime detection. The market regime S_t ∈ \{1, ..., K\} is unobserved (hidden), but the returns r_t are observed. The model specifies:
P(S\_t = j | S\_{t-1} = i) = A\_\{ij\} (transition matrix) r\_t | S\_t = k ~ N(μ\_k, σ\_k²) (regime-conditional return distribution)
The Viterbi algorithm decodes the most likely regime sequence given observed returns. The forward-backward algorithm computes P(S\_t = k | r\_\{1:T\}) — the regime probability at time t given all returns.
Alternative approaches include:
- GARCH-based vol regimes: threshold on garch_vol_21d percentile
- K-means / GMM clustering on features (volatility, trend, breadth)
- Structural break tests (Chow, CUSUM)
- ML classifiers (gradient boosting on technical features)
Regime persistence matters: transition probabilities should show high diagonal values (regimes last weeks to months, not days). Overfitting to noisy regime boundaries is the primary practical failure mode.
How VectorFin Uses This
VectorFin's signals/regime table provides daily regime classifications for individual tickers and market-level indices. Each row contains:
regime: one ofbull,bear,volatile,sidewaysconfidence: probability from the underlying HMM (0.0-1.0)effective_ts: the business dateknowledge_ts: when VectorFin computed this signal (for backtest safety)
The table is populated nightly via the signals_writer Cloud Run Job, which fits an HMM using daily returns, GARCH volatility forecasts, and breadth indicators.
GET https://api.vectorfinancials.com/v1/signals/regime/{ticker}?date=2024-10-01
GET https://api.vectorfinancials.com/v1/signals/regime/{ticker}?start=2024-01-01&end=2024-12-31Strategy applications: use the regime signal to switch between factor tilts, adjust leverage, or activate/deactivate momentum overlays based on current market conditions.
Code Example
import requests
import pandas as pd
import matplotlib.pyplot as plt
API_BASE = "https://api.vectorfinancials.com"
API_KEY = "vf_your_api_key_here"
# Fetch full year of regime history for SPY (market-level proxy)
resp = requests.get(
f"{API_BASE}/v1/signals/regime/SPY",
params={"start": "2024-01-01", "end": "2024-12-31"},
headers={"X-API-Key": API_KEY},
)
df = pd.DataFrame(resp.json()["data"])
df["date"] = pd.to_datetime(df["date"])
# Regime distribution
print("Regime distribution (SPY 2024):")
print(df["regime"].value_counts(normalize=True).round(3))
# Days in high-confidence regime (confidence > 0.70)
high_confidence = df[df["confidence"] > 0.70]
print(f"\nHigh-confidence regime days: {len(high_confidence)} / {len(df)}")
print(high_confidence["regime"].value_counts())
# Strategy: only trade momentum when regime is bull or sideways
tradeable_dates = df[df["regime"].isin(["bull", "sideways"])]["date"].tolist()
print(f"\nDates where momentum strategy is active: {len(tradeable_dates)}")Related Terms
Put Regime Detection to work in your pipeline
Access AI-ready financial data — embeddings, signals, Iceberg tables.