Перейти к содержимому

Скрытые Марковские модели (HMM) для определения рыночных режимов

Эта глава представляет скрытые Марковские модели (Hidden Markov Models, HMM) для определения рыночных режимов и построения адаптивных торговых стратегий. Финансовые рынки функционируют в различных режимах (бычий, медвежий, боковой), каждый со своими статистическими характеристиками. HMM позволяют автоматически определять текущий режим и вероятности перехода между режимами.

Содержание

  1. Введение в рыночные режимы
  2. Теория скрытых Марковских моделей
  3. Алгоритмы HMM
  4. Определение рыночных режимов
  5. Торговая стратегия
  6. Примеры кода
  7. Реализация на Rust
  8. Практические соображения
  9. Ресурсы

Введение в рыночные режимы

Что такое рыночный режим?

Рыночный режим — это состояние рынка, характеризующееся определённым набором статистических свойств:

РежимХарактеристикиТипичные индикаторы
Бычий (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 определяется тремя наборами параметров:

  1. Начальное распределение π: Вероятность начать в каждом состоянии $$\pi_i = P(Z_1 = i)$$

  2. Матрица переходов A: Вероятности переходов между состояниями $$a_{ij} = P(Z_{t+1} = j | Z_t = i)$$

  3. Распределения эмиссий 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.ipynbFeature engineering для определения режимов
04_gaussian_hmm.ipynbОбучение Gaussian HMM с hmmlearn
05_regime_interpretation.ipynbИнтерпретация режимов, визуализация
06_regime_characteristics.ipynbСтатистика каждого режима (return, vol, duration)
07_substrategy_bull.ipynbMomentum стратегия для bull режима
08_substrategy_bear.ipynbDefensive стратегия для bear режима
09_substrategy_sideways.ipynbMean-reversion для sideways режима
10_strategy_switching.ipynbЛогика переключения между стратегиями
11_backtesting.ipynbFull backtest с transaction costs
12_robustness_analysis.ipynbSensitivity 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+ лет)
  • Сильно нестационарные рынки

Подводные камни

  1. Look-ahead bias: Не используйте будущие данные для определения режима!

  2. Label switching: HMM не гарантирует, что состояние 0 — всегда Bull. Нужно интерпретировать.

  3. Overfitting: Слишком много состояний → переобучение. 2-4 состояния оптимально.

  4. Whipsaws: Частые переключения = большие transaction costs. Используйте сглаживание.

  5. Изменение динамики: Режимы 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)

Ресурсы

Статьи

Библиотеки

Связанные главы


Зависимости

# Python
hmmlearn>=0.3.0
pomegranate>=1.0.0
pandas>=1.5.0
numpy>=1.23.0
matplotlib>=3.6.0
seaborn>=0.12.0
scipy>=1.10.0
yfinance>=0.2.0
scikit-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 недели