Skip to main content
Pro Feature. Requires a Pro or Ultra subscription. Get started at api.mathematicalcompany.com

Markov Regime Detection

Horizon includes a Hidden Markov Model (HMM) with Gaussian emissions, implemented entirely in Rust. It classifies the current market into regimes (e.g., calm vs. volatile) in real time, with a per-tick cost of O(N^2) where N is the number of states (typically 2-3).
Regime detection lets your strategy adapt its behavior to market conditions. Widen spreads in volatile regimes, reduce size in crisis regimes, or disable quoting entirely when the model signals a regime change.

Overview

Rust HMM

Full Baum-Welch EM training, Viterbi decoding, forward-backward smoothing. All in Rust with zero Python overhead.

O(N^2) Online Filter

Per-tick forward filter costs ~9 multiplies for 3 states. Effectively zero latency added to your pipeline.

Auto-Train Mode

No pre-trained model? Collect prices during warmup and train inline. Works in both live and backtest.

Pipeline Integration

Drop hz.markov_regime() into any pipeline. Injects regime info into ctx.params for downstream use.

Quick Start

Pre-Trained Model

Train offline on historical returns, then use in live trading:

Auto-Train Mode

No historical data? Train inline during warmup:
The model collects 200 price ticks, computes log returns, trains the HMM, then starts classifying. Before training completes, ctx.params["regime"] is not set.

MarkovRegimeModel (Rust)

The core HMM class. Use this directly for offline analysis, or pass it to hz.markov_regime() for pipeline use.

Constructor

fit()

Train the model using Baum-Welch EM on a series of observations (log returns).
Returns the final log-likelihood. States are automatically sorted by variance after training (state 0 = lowest variance = calmest regime).

decode()

Find the most likely state sequence using the Viterbi algorithm.
Returns a list of state indices (0 to n_states-1) for each observation.

filter_step()

Online forward filter. Process one observation and update state probabilities. This is the hot path for live trading.
Returns a list of state probabilities (sums to 1.0).

predict()

One-step-ahead prediction: given the current filtered state, what are the probabilities for the next time step?

smooth()

Full forward-backward smoothing on a batch of observations. More accurate than filtering alone.

Other Methods


hz.prices_to_returns

Convenience function to convert a price series to log returns.
Handles zero prices gracefully (returns 0.0 for that period). Requires at least 2 prices.

hz.markov_regime() Pipeline Factory

Creates a pipeline function that classifies the current regime on each tick.

Injected Parameters

After training and sufficient data, the function injects:

Examples

Regime-Adaptive Market Maker

Widen spreads in volatile regimes:

Regime-Gated Trading

Only trade in calm regimes:

Backtest with Regime Detection

Offline Analysis

Use the HMM directly for research without a pipeline:

Mathematical Background

An HMM models a system that transitions between N hidden states. At each time step:
  1. The system transitions from state i to state j with probability A[i][j] (transition matrix)
  2. In state j, it emits an observation from a Gaussian distribution N(mu_j, sigma^2_j)
The model parameters are: initial state probabilities (pi), transition matrix (A), and emission parameters (mu, sigma^2) for each state.
The Baum-Welch algorithm (a special case of EM) iteratively:
  1. E-step: Run forward-backward to compute state occupation probabilities given current parameters
  2. M-step: Re-estimate parameters (A, mu, sigma^2) from the occupation probabilities
Converges to a local maximum of the observation likelihood. Horizon uses quantile-based initialization to improve convergence.
The Viterbi algorithm finds the single most likely state sequence using dynamic programming. Runs in O(T * N^2) time where T is the sequence length and N is the number of states.
The forward filter recursively computes P(state_t | observations_1..t):
Then normalize: P(state_t = j) = alpha_t(j) / sum(alpha_t). This is O(N^2) per time step. For N=3 (typical), that’s 9 multiplies plus normalization.
HMMs assume stationary dynamics. If market regimes shift structurally (e.g., new regulation), retrain the model periodically. Use the auto-train mode with a reasonable warmup for adaptive behavior.