GaussianHMM из библиотеки hmmlearn для определения рыночных режимов и симулирует торговлю с учетом задержки на исполнение ордеров.Исходный код
Скрытые марковские модели (Hidden Markov Models, HMM) отлично подходят для поиска скрытых состояний рынка (например: бычий тренд с низкой волатильностью, медвежий тренд с высокой волатильностью или флэт). В отличие от статической кластеризации, подробнее о которой можно узнать в статье Кластеризация криптовалют по волатильности на Python с K-Means, HMM учитывает временную последовательность и вероятности переходов между состояниями.
Ниже представлен профессиональный скрипт для бэктестинга HMM-стратегии на исторических данных индекса S&P 500 (SPY):
import numpy as np
import pandas as pd
import yfinance as yf
from hmmlearn.hmm import GaussianHMM
import matplotlib.pyplot as plt
def run_hmm_backtest():
# 1. Загрузка исторических данных
ticker = "SPY"
data = yf.download(ticker, start="2015-01-01", end="2023-12-31")
# Вычисляем признаки (features) для HMM
# Логарифмическая доходность
data['Returns'] = np.log(data['Close'] / data['Close'].shift(1))
# Логарифмический размах (прокси для волатильности)
data['Range'] = np.log(data['High'] / data['Low'])
data.dropna(inplace=True)
# Формируем матрицу признаков
X = data[['Returns', 'Range']].values
# 2. Инициализация и обучение Gaussian HMM
# Выбираем 3 режима: например, рост/низкая вол., флэт, падение/высокая вол.
model = GaussianHMM(n_components=3, covariance_type="full", n_iter=100, random_state=42)
model.fit(X)
# Предсказываем скрытые состояния
data['State'] = model.predict(X)
# 3. Анализ полученных состояний для построения сигналов
# Определяем среднюю доходность для каждого состояния
state_means = data.groupby('State')['Returns'].mean()
print("Средняя доходность по состояниям:\n", state_means)
# Находим индекс "лучшего" (бычьего) и "худшего" (медвежьего) состояний
bull_state = state_means.idxmax()
bear_state = state_means.idxmin()
# Формируем сигналы:
# +1 (long) в бычьем состоянии, -1 (short) в медвежьем, 0 (flat) в нейтральном
data['Signal'] = 0
data.loc[data['State'] == bull_state, 'Signal'] = 1
data.loc[data['State'] == bear_state, 'Signal'] = -1
# Важно: сдвигаем сигнал на 1 день вперед, чтобы избежать look-ahead bias (заглядывания в будущее)
data['Signal'] = data['Signal'].shift(1)
data.dropna(inplace=True)
# 4. Расчет доходности стратегии
data['Strategy_Returns'] = data['Signal'] * data['Returns']
# Кумулятивная доходность
data['Cum_Market'] = data['Returns'].cumsum().apply(np.exp) - 1
data['Cum_Strategy'] = data['Strategy_Returns'].cumsum().apply(np.exp) - 1
# 5. Визуализация результатов
plt.figure(figsize=(12, 6))
plt.plot(data.index, data['Cum_Market'] * 100, label='Market (Buy & Hold)', color='gray', alpha=0.7)
plt.plot(data.index, data['Cum_Strategy'] * 100, label='HMM Regime Strategy', color='blue')
plt.title(f"HMM Regime Switching Strategy Backtest on {ticker}")
plt.xlabel("Date")
plt.ylabel("Cumulative Return (%)")
plt.legend()
plt.grid(True)
plt.show()
# Вывод метрик
sharpe_market = (data['Returns'].mean() / data['Returns'].std()) * np.sqrt(252)
sharpe_strategy = (data['Strategy_Returns'].mean() / data['Strategy_Returns'].std()) * np.sqrt(252)
print(f"Sharpe Ratio (Market): {sharpe_market:.2f}")
print(f"Sharpe Ratio (Strategy): {sharpe_strategy:.2f}")
if __name__ == "__main__":
run_hmm_backtest() Разбор параметров
n_components: Количество скрытых состояний модели. В данном примере установлено значение3(например: бычий тренд, медвежий тренд, боковик). Увеличение числа компонентов может привести к переобучению (overfitting).covariance_type: Тип ковариационной матрицы, определяющий связь между признаками. Значение'full'позволяет моделировать сложные нелинейные взаимосвязи между доходностью и волатильностью для каждого состояния.n_iter: Максимальное количество итераций алгоритма Expectation-Maximization (EM) для сходимости параметров модели.random_state: Фиксированный сид генератора случайных чисел для обеспечения воспроизводимости результатов кластеризации при каждом запуске.shift(1): Критически важный шаг в бэктестинге. Сдвигает торговый сигнал на один шаг вперед, гарантируя, что позиция открывается по цене открытия следующего дня после фиксации состояния рынка, исключая заглядывание в будущее.
Как запустить
Для запуска скрипта вам понадобится Python версии 3.8 или выше. Установите необходимые библиотеки с помощью пакетного менеджера pip:
pip install numpy pandas yfinance hmmlearn matplotlib После установки зависимостей сохраните приведенный выше код в файл с именем hmm_backtest.py и запустите его из терминала:
python hmm_backtest.py Скрипт автоматически загрузит котировки ETF SPY, обучит марковскую модель, рассчитает метрики эффективности (включая коэффициент Шарпа) и построит интерактивный график сравнения доходности стратегии с пассивным удержанием актива.




