Скрытые Марковские модели (HMM) для определения рыночных режимов
Эта глава представляет скрытые Марковские модели (Hidden Markov Models, HMM) для определения рыночных режимов и построения адаптивных торговых стратегий. Финансовые рынки функционируют в различных режимах (бычий, медвежий, боковой), каждый со своими статистическими характеристиками. HMM позволяют автоматически определять текущий режим и вероятности перехода между режимами.
Содержание
- Введение в рыночные режимы
- Теория скрытых Марковских моделей
- Алгоритмы HMM
- Определение рыночных режимов
- Торговая стратегия
- Примеры кода
- Реализация на Rust
- Практические соображения
- Ресурсы
Введение в рыночные режимы
Что такое рыночный режим?
Рыночный режим — это состояние рынка, характеризующееся определённым набором статистических свойств:
| Режим | Характеристики | Типичные индикаторы |
|---|---|---|
| Бычий (Bull) | Восходящий тренд, низкая волатильность, оптимизм | Низкий VIX, крутая кривая доходности |
| Медвежий (Bear) | Нисходящий тренд, высокая волатильность, страх | Высокий VIX, инвертированная кривая |
| Боковой (Sideways) | Отсутствие тренда, средняя волатильность | Средний VIX, плоская кривая |
Почему режимы важны для трейдинга?
Одна и та же стратегия работает по-разному в разных режимах:
Momentum стратегия:├── Bull режим: Отлично работает ✅ (+25% годовых)├── Bear режим: Катастрофа ❌ (-40% годовых)└── Sideways режим: Убытки на комиссиях ⚠️ (-5% годовых)
Mean-reversion стратегия:├── Bull режим: Упущенная прибыль ⚠️ (+5% годовых)├── Bear режим: Средне 🔶 (+10% годовых)└── Sideways режим: Отлично работает ✅ (+20% годовых)Ключевая идея: Вместо одной стратегии на все случаи жизни — адаптироваться к текущему режиму!
Исторические примеры смены режимов
S&P 500 (2000-2024):├── 2003-2007: Bull (технологический рост)├── 2008-2009: Bear (финансовый кризис)├── 2010-2019: Bull (QE-эра)├── 2020 Q1: Bear (COVID crash)├── 2020-2021: Bull (стимулы)├── 2022: Bear (инфляция, ставки)└── 2023-2024: Bull (AI-ралли)
Bitcoin (2017-2024):├── 2017: Bull ($1k → $20k)├── 2018: Bear ($20k → $3k)├── 2019: Sideways ($3k-$12k)├── 2020-2021: Bull ($10k → $69k)├── 2022: Bear ($69k → $16k)└── 2023-2024: Bull ($16k → $70k+)Теория скрытых Марковских моделей
Марковские цепи
Марковское свойство: будущее состояние зависит только от текущего состояния, не от всей истории.
$$P(S_{t+1} | S_t, S_{t-1}, …, S_1) = P(S_{t+1} | S_t)$$
Это упрощающее предположение, которое делает модель вычислительно tractable.
Скрытые состояния vs наблюдаемые переменные
В HMM мы различаем:
- Скрытые состояния (Z): Истинный режим рынка (Bull/Bear/Sideways) — мы не наблюдаем напрямую
- Наблюдаемые переменные (X): Доходности, волатильность, VIX и другие измеримые величины
Скрытые состояния: [Bull] → [Bull] → [Bear] → [Bear] → [Sideways] ↓ ↓ ↓ ↓ ↓Наблюдения: +2% +1% -3% -2% +0.5%Параметры HMM
HMM определяется тремя наборами параметров:
-
Начальное распределение π: Вероятность начать в каждом состоянии $$\pi_i = P(Z_1 = i)$$
-
Матрица переходов A: Вероятности переходов между состояниями $$a_{ij} = P(Z_{t+1} = j | Z_t = i)$$
-
Распределения эмиссий B: Как каждое состояние генерирует наблюдения
- Для Gaussian HMM: $b_i(x) = \mathcal{N}(x; \mu_i, \Sigma_i)$
Три фундаментальные проблемы HMM
| Проблема | Описание | Алгоритм |
|---|---|---|
| Оценка | Какова вероятность наблюдаемой последовательности? | Forward-Backward |
| Декодирование | Какая наиболее вероятная последовательность состояний? | Viterbi |
| Обучение | Какие параметры максимизируют правдоподобие? | Baum-Welch (EM) |
Алгоритмы HMM
Forward-Backward алгоритм
Вычисляет вероятность наблюдений и апостериорные вероятности состояний.
Forward переменные: $$\alpha_t(i) = P(X_1, …, X_t, Z_t = i)$$
Backward переменные: $$\beta_t(i) = P(X_{t+1}, …, X_T | Z_t = i)$$
Апостериорная вероятность состояния: $$\gamma_t(i) = P(Z_t = i | X_1, …, X_T) = \frac{\alpha_t(i) \beta_t(i)}{\sum_j \alpha_t(j) \beta_t(j)}$$
Алгоритм Витерби
Находит наиболее вероятную последовательность скрытых состояний (динамическое программирование):
def viterbi(observations, hmm): # Инициализация delta[0] = pi * B(observations[0])
# Рекурсия for t in range(1, T): for j in range(N): delta[t, j] = max_i(delta[t-1, i] * A[i,j]) * B_j(observations[t]) psi[t, j] = argmax_i(delta[t-1, i] * A[i,j])
# Backtracking path[T-1] = argmax(delta[T-1]) for t in range(T-2, -1, -1): path[t] = psi[t+1, path[t+1]]
return pathАлгоритм Баума-Велша (EM)
Итеративно улучшает параметры модели:
E-шаг: Вычислить ожидаемые статистики с текущими параметрами
- $\gamma_t(i)$ — вероятность быть в состоянии i в момент t
- $\xi_t(i,j)$ — вероятность перехода i→j в момент t
M-шаг: Обновить параметры $$\hat{a}{ij} = \frac{\sum{t=1}^{T-1} \xi_t(i,j)}{\sum_{t=1}^{T-1} \gamma_t(i)}$$
$$\hat{\mu}i = \frac{\sum{t=1}^{T} \gamma_t(i) x_t}{\sum_{t=1}^{T} \gamma_t(i)}$$
Определение рыночных режимов
Выбор признаков для режимов
Хорошие признаки для определения режимов:
features = [ 'return_20d', # 20-дневная доходность (тренд) 'volatility_20d', # 20-дневная волатильность (риск) 'vix_level', # Индекс страха (сентимент) 'yield_slope', # Наклон кривой доходности (макро) 'credit_spread', # Кредитный спред (риск-аппетит) 'rsi_14', # RSI (перекупленность/перепроданность) 'macd_signal', # MACD (моментум) 'volume_ratio' # Объём относительно среднего]Gaussian HMM для непрерывных данных
from hmmlearn import hmm
# Конфигурация 3-режимной моделиmodel = hmm.GaussianHMM( n_components=3, # Bull, Bear, Sideways covariance_type="full", # Полная ковариационная матрица n_iter=1000, # Итераций EM random_state=42, tol=1e-4 # Порог сходимости)
# Обучение на исторических данныхmodel.fit(features_scaled)
# Декодирование режимовhidden_states = model.predict(features_scaled)state_probs = model.predict_proba(features_scaled)Интерпретация режимов
После обучения нужно интерпретировать, какое состояние соответствует какому режиму:
# Анализ средних значений каждого состоянияfor i in range(model.n_components): mask = hidden_states == i avg_return = returns[mask].mean() * 252 # Годовая доходность avg_vol = volatility[mask].mean() * np.sqrt(252) # Годовая волатильность
if avg_return > 0.10 and avg_vol < 0.20: regime_names[i] = "Bull" elif avg_return < -0.10 or avg_vol > 0.25: regime_names[i] = "Bear" else: regime_names[i] = "Sideways"Характеристики режимов (ожидаемые)
| Режим | Годовая доходность | Волатильность | Средняя длительность |
|---|---|---|---|
| Bull | +15% | 12% | 24 месяца |
| Bear | -20% | 25% | 8 месяцев |
| Sideways | +5% | 15% | 12 месяцев |
Матрица переходов (пример)
К Bull К Bear К SidewaysОт Bull 0.92 0.03 0.05От Bear 0.08 0.85 0.07От Sideways 0.10 0.08 0.82Интерпретация:
- Bull режим самый “липкий” (92% вероятность остаться)
- Bear режим быстрее заканчивается (15% вероятность перехода)
- Переход Bear → Bull редок (8%), обычно через Sideways
Торговая стратегия
Суть стратегии
HMM определяет текущий режим → выбираем соответствующую подстратегию:
┌─────────────────┐│ HMM Detector ││ (режим + prob) │└────────┬────────┘ │ ┌────┴────┐ ▼ ▼ ▼┌───────┐ ┌───────┐ ┌───────┐│ Bull │ │ Bear │ │Sideways││Strategy│ │Strategy│ │Strategy│└───────┘ └───────┘ └───────┘ │ │ │ └────┬────┴────┬────┘ ▼ Portfolio WeightsПодстратегия для бычьего режима
Цель: Максимизировать exposure к растущему рынку
bull_strategy = { 'equity_allocation': 1.0, # 100% акций 'factor_tilts': ['momentum', 'small_cap'], 'hedges': None, 'leverage': 1.0, # Без плеча 'rebalance_freq': 'monthly'}Компоненты:
- Long equity (100% allocation)
- Momentum factor tilt
- Small cap overweight
- Без хеджей
Подстратегия для медвежьего режима
Цель: Защита капитала, минимизация просадки
bear_strategy = { 'equity_allocation': 0.30, # Только 30% акций 'bonds_allocation': 0.40, # 40% в длинных облигациях 'gold_allocation': 0.20, # 20% в золоте 'cash_allocation': 0.10, # 10% кэш 'hedges': ['vix_calls'], # Опционы на VIX}Компоненты:
- Reduced equity (30% allocation)
- Long-term treasuries (40%)
- Gold allocation (20%)
- Cash buffer (10%)
- VIX calls hedge
Подстратегия для бокового режима
Цель: Извлечение альфы из mean-reversion
sideways_strategy = { 'equity_allocation': 0.50, # 50% акций 'pairs_trading': True, # Парный трейдинг 'sector_rotation': True, # Ротация секторов 'mean_reversion': True, # Mean-reversion сигналы}Компоненты:
- Market neutral (50% equity)
- Pairs trading overlay
- Sector rotation
- Enhanced yield strategies
Логика переключения стратегий
def get_current_strategy(state_probs, current_positions): """ Определяет текущую стратегию с учётом: 1. Posterior probability режима (сглаженная) 2. Порога переключения 3. Минимального времени в режиме (против whipsaws) 4. Transaction costs """
# Сглаживание вероятностей smoothed_probs = ema(state_probs, span=5)
# Определение доминирующего режима dominant_regime = np.argmax(smoothed_probs) confidence = smoothed_probs[dominant_regime]
# Переключение только при высокой уверенности if confidence > SWITCH_THRESHOLD: # например, 0.70 if time_in_regime > MIN_REGIME_DURATION: # минимум 5 дней return strategies[dominant_regime]
# Иначе остаёмся в текущей стратегии return current_strategyПримеры кода
| Ноутбук | Описание |
|---|---|
| 01_data_preparation.ipynb | Загрузка S&P 500, VIX, yields, macro данных |
| 02_hmm_theory.ipynb | Теория HMM: forward-backward, Viterbi, Baum-Welch |
| 03_regime_features.ipynb | Feature engineering для определения режимов |
| 04_gaussian_hmm.ipynb | Обучение Gaussian HMM с hmmlearn |
| 05_regime_interpretation.ipynb | Интерпретация режимов, визуализация |
| 06_regime_characteristics.ipynb | Статистика каждого режима (return, vol, duration) |
| 07_substrategy_bull.ipynb | Momentum стратегия для bull режима |
| 08_substrategy_bear.ipynb | Defensive стратегия для bear режима |
| 09_substrategy_sideways.ipynb | Mean-reversion для sideways режима |
| 10_strategy_switching.ipynb | Логика переключения между стратегиями |
| 11_backtesting.ipynb | Full backtest с transaction costs |
| 12_robustness_analysis.ipynb | Sensitivity analysis, out-of-sample |
Реализация на Rust
Директория rust_hmm_trading содержит полную Rust-реализацию для криптовалютного рынка (Bybit):
rust_hmm_trading/├── Cargo.toml # Зависимости проекта├── README.md # Документация Rust-проекта├── src/│ ├── lib.rs # Главный модуль библиотеки│ ├── main.rs # CLI приложение│ ├── api/ # Bybit API клиент│ │ ├── mod.rs│ │ ├── bybit.rs # Клиент для Bybit│ │ └── error.rs # Типы ошибок│ ├── data/ # Работа с данными│ │ ├── mod.rs│ │ ├── types.rs # Candle, OHLCV, Dataset│ │ └── features.rs # Feature engineering│ ├── models/ # HMM модели│ │ ├── mod.rs│ │ ├── hmm.rs # Основная HMM реализация│ │ ├── gaussian.rs # Gaussian emissions│ │ └── algorithms.rs # Viterbi, Forward-Backward, Baum-Welch│ ├── regime/ # Определение режимов│ │ ├── mod.rs│ │ ├── detector.rs # Детектор режимов│ │ └── interpreter.rs # Интерпретация состояний│ ├── strategies/ # Торговые стратегии│ │ ├── mod.rs│ │ ├── bull.rs # Бычья стратегия│ │ ├── bear.rs # Медвежья стратегия│ │ ├── sideways.rs # Боковая стратегия│ │ └── switcher.rs # Логика переключения│ └── trading/ # Бэктестинг│ ├── mod.rs│ ├── backtest.rs # Бэктестер│ ├── metrics.rs # Метрики (Sharpe, Drawdown)│ └── portfolio.rs # Управление портфелем└── examples/ ├── fetch_data.rs # Загрузка данных с Bybit ├── train_hmm.rs # Обучение HMM ├── detect_regimes.rs # Определение режимов └── full_backtest.rs # Полный бэктест стратегииСмотрите rust_hmm_trading/README.md для подробностей.
Практические соображения
Когда использовать HMM для режимов
Хорошие кейсы:
- Долгосрочные стратегии (ребалансировка раз в месяц)
- Adaptive asset allocation
- Tail-risk hedging (переключение на защитные активы)
- Определение “рыночной погоды” для принятия решений
Не идеально для:
- High-frequency trading (слишком медленно реагирует)
- Когда нужна детерминированная логика
- При недостатке исторических данных (нужно 10+ лет)
- Сильно нестационарные рынки
Подводные камни
-
Look-ahead bias: Не используйте будущие данные для определения режима!
-
Label switching: HMM не гарантирует, что состояние 0 — всегда Bull. Нужно интерпретировать.
-
Overfitting: Слишком много состояний → переобучение. 2-4 состояния оптимально.
-
Whipsaws: Частые переключения = большие transaction costs. Используйте сглаживание.
-
Изменение динамики: Режимы 2008 года ≠ режимы 2024 года. Нужна переобучение.
Выбор количества состояний
| Состояний | Плюсы | Минусы |
|---|---|---|
| 2 | Простота, робастность | Теряем Sideways |
| 3 | Интуитивно (Bull/Bear/Sideways) | Стандартный выбор |
| 4 | Различаем High/Low волатильность | Сложнее интерпретировать |
| 5+ | Больше нюансов | Переобучение, нестабильность |
Рекомендация: Начните с 3 состояний, используйте AIC/BIC для валидации.
Метрики оценки
Для детекции режимов:
- Accuracy vs NBER recession dates
- Average regime duration (реалистично ли?)
- False switch rate
Для стратегии:
- Sharpe Ratio (>1.0 желательно)
- Max Drawdown (<20% желательно)
- Calmar Ratio (Return/MaxDD)
- Comparison vs benchmarks (Buy&Hold, 60/40)
Ресурсы
Статьи
- Regime Switching Models for Financial Time Series — Hamilton, 1989
- Hidden Markov Models for Time Series — Zucchini et al.
- Market Regime Detection Using Machine Learning — JPM Research
- Detecting Regime Changes in Financial Markets — Ardia et al., 2019
Библиотеки
- hmmlearn — Python HMM library
- pomegranate — Probabilistic models including HMM
- PyPortfolioOpt — Portfolio optimization
Связанные главы
- Глава 09: Модели временных рядов — ARIMA, GARCH для волатильности
- Глава 10: Байесовское машинное обучение — Вероятностные подходы
- Глава 11: Random Forests — Альтернативные классификаторы режимов
- Глава 23: Обучение с подкреплением — Адаптивные стратегии
Зависимости
# Pythonhmmlearn>=0.3.0pomegranate>=1.0.0pandas>=1.5.0numpy>=1.23.0matplotlib>=3.6.0seaborn>=0.12.0scipy>=1.10.0yfinance>=0.2.0scikit-learn>=1.2.0# Rust (Cargo.toml)ndarray = "0.15"ndarray-linalg = "0.16"statrs = "0.16"reqwest = { version = "0.11", features = ["json"] }tokio = { version = "1", features = ["full"] }serde = { version = "1.0", features = ["derive"] }Уровень сложности
⭐⭐⭐☆☆ (Средний)
Требуется понимание:
- Теория вероятностей (Марковские процессы)
- Алгоритм EM (Expectation-Maximization)
- Time series analysis
- Portfolio construction
Время освоения: 2-3 недели