파이썬 HMM 시장 레짐 탐지

시장 레짐 탐지란?

퀀트 트레이딩에서 시장 레짐(Market Regime)이란 시장이 특정 기간 동안 보이는 통계적 특성을 말합니다. 대표적으로 상승 추세(Bull), 하락 추세(Bear), 횡보(Sideways) 세 가지 레짐으로 구분합니다. 레짐에 따라 최적의 전략이 달라지기 때문에, 현재 시장이 어떤 레짐에 있는지 자동으로 탐지하는 것은 퀀트 자동매매 시스템의 핵심 모듈입니다.

단순 이동평균이나 RSI로는 레짐 전환을 정확히 포착하기 어렵습니다. 이 글에서는 은닉 마르코프 모델(Hidden Markov Model, HMM)을 사용해 파이썬으로 시장 레짐을 탐지하고, 이를 자동매매 전략에 적용하는 방법을 단계별로 설명합니다.

HMM(은닉 마르코프 모델) 핵심 개념

HMM은 관측할 수 없는 숨겨진 상태(hidden state)가 시간에 따라 전이되며, 각 상태에서 관측 가능한 데이터가 생성된다고 가정하는 확률 모델입니다. 금융 시장에 적용하면:

  • 숨겨진 상태: Bull, Bear, Sideways 레짐
  • 관측 데이터: 일별 수익률, 변동성 등
  • 전이 확률(Transition Probability): 레짐 간 전환 확률
  • 방출 확률(Emission Probability): 각 레짐에서 수익률 분포

HMM의 핵심 가정은 마르코프 성질입니다. 내일의 레짐은 오늘의 레짐에만 의존하며, 과거 전체 이력에 의존하지 않습니다. 이 단순한 가정이 놀라울 정도로 시장 레짐 전환을 잘 포착합니다.

파이썬 환경 설정

HMM 구현에 필요한 라이브러리를 설치합니다:

pip install hmmlearn numpy pandas yfinance matplotlib scikit-learn

hmmlearn은 scikit-learn 기반의 HMM 구현 라이브러리로, 가우시안 HMM을 간편하게 사용할 수 있습니다.

데이터 수집 및 전처리

먼저 주가 데이터를 가져와 HMM 입력 피처를 생성합니다:

import numpy as np
import pandas as pd
import yfinance as yf
from hmmlearn.hmm import GaussianHMM

# S&P 500 데이터 수집
data = yf.download("SPY", start="2015-01-01", end="2025-12-31")

# 피처 엔지니어링
data["returns"] = data["Close"].pct_change()
data["volatility"] = data["returns"].rolling(20).std()
data["volume_change"] = data["Volume"].pct_change()
data.dropna(inplace=True)

# HMM 입력: 수익률 + 변동성 + 거래량 변화
features = data[["returns", "volatility", "volume_change"]].values
print(f"데이터 shape: {features.shape}")

피처 선택이 핵심입니다. 수익률만 사용하면 노이즈에 취약하므로, 변동성거래량 변화를 함께 사용해 레짐 탐지의 정확도를 높입니다.

가우시안 HMM 학습

3개 레짐(Bull, Bear, Sideways)을 가정하고 모델을 학습합니다:

# 3-state Gaussian HMM 학습
model = GaussianHMM(
    n_components=3,       # 레짐 수
    covariance_type="full",  # 피처 간 상관관계 반영
    n_iter=200,
    random_state=42
)
model.fit(features)

# 각 시점의 레짐 예측
hidden_states = model.predict(features)
data["regime"] = hidden_states

# 레짐별 통계
for i in range(3):
    mask = data["regime"] == i
    mean_ret = data.loc[mask, "returns"].mean() * 252  # 연환산
    mean_vol = data.loc[mask, "volatility"].mean() * np.sqrt(252)
    count = mask.sum()
    print(f"레짐 {i}: 연수익률={mean_ret:.1%}, "
          f"연변동성={mean_vol:.1%}, 일수={count}")

학습 결과 각 레짐은 뚜렷한 특성을 보입니다. 일반적으로 높은 수익률+낮은 변동성(Bull), 낮은 수익률+높은 변동성(Bear), 중간 수익률+중간 변동성(Sideways)으로 분류됩니다.

레짐 전이 확률 분석

HMM의 전이 행렬(Transition Matrix)은 레짐 간 전환 패턴을 보여줍니다:

# 전이 확률 행렬
trans_mat = model.transmat_
regime_names = ["Bull", "Bear", "Sideways"]

print("=== 전이 확률 행렬 ===")
for i, name_from in enumerate(regime_names):
    for j, name_to in enumerate(regime_names):
        print(f"  {name_from} → {name_to}: {trans_mat[i][j]:.3f}")

# 레짐 지속 기간 추정
for i, name in enumerate(regime_names):
    duration = 1 / (1 - trans_mat[i][i])
    print(f"{name} 평균 지속: {duration:.1f}일")

전이 행렬에서 대각선 값이 높을수록 해당 레짐이 오래 지속됩니다. 보통 Bull 레짐은 수개월, Bear 레짐은 수주 단위로 지속되는 패턴을 보입니다. 이 정보를 활용하면 레짐 전환 시점을 예측할 수 있습니다.

레짐 기반 자동매매 전략

탐지된 레짐에 따라 포지션을 조절하는 전략을 구현합니다:

def regime_strategy(data, model, features):
    """레짐 기반 포지션 관리"""
    # 레짐별 포지션 비중
    position_map = {
        0: 1.0,   # Bull → 풀 포지션
        1: -0.5,  # Bear → 숏 또는 헤지
        2: 0.3,   # Sideways → 축소 포지션
    }

    # 레짐 확률 기반 가중 포지션
    probs = model.predict_proba(features)
    positions = np.zeros(len(data))

    for regime, weight in position_map.items():
        positions += probs[:, regime] * weight

    data["position"] = positions
    data["strategy_returns"] = data["position"].shift(1) * data["returns"]
    return data

data = regime_strategy(data, model, features)

# 성과 비교
buy_hold = (1 + data["returns"]).cumprod().iloc[-1] - 1
strategy = (1 + data["strategy_returns"].dropna()).cumprod().iloc[-1] - 1
print(f"Buy & Hold 수익률: {buy_hold:.1%}")
print(f"레짐 전략 수익률: {strategy:.1%}")

핵심은 확률 기반 포지션 조절입니다. 단순히 “Bull이면 매수”가 아니라, 각 레짐의 확률값을 가중 평균해 포지션 크기를 결정합니다. 이렇게 하면 레짐 전환기에 급격한 포지션 변동을 방지할 수 있습니다.

실시간 레짐 모니터링 시스템

학습된 모델을 실시간으로 활용하는 모니터링 코드입니다:

import json
from datetime import datetime

class RegimeMonitor:
    def __init__(self, model, lookback=60):
        self.model = model
        self.lookback = lookback

    def detect(self, recent_data):
        """최근 데이터로 현재 레짐 탐지"""
        features = recent_data[
            ["returns", "volatility", "volume_change"]
        ].values[-self.lookback:]

        probs = self.model.predict_proba(features)
        current_probs = probs[-1]
        current_regime = np.argmax(current_probs)

        return {
            "timestamp": datetime.now().isoformat(),
            "regime": int(current_regime),
            "regime_name": ["Bull", "Bear", "Sideways"][current_regime],
            "probabilities": {
                "bull": round(float(current_probs[0]), 3),
                "bear": round(float(current_probs[1]), 3),
                "sideways": round(float(current_probs[2]), 3),
            },
            "confidence": round(float(max(current_probs)), 3),
        }

# 사용 예시
monitor = RegimeMonitor(model)
result = monitor.detect(data)
print(json.dumps(result, indent=2, ensure_ascii=False))

이 모니터링 시스템을 스케줄러(cron 또는 APScheduler)와 연결하면, 매일 장 마감 후 자동으로 레짐을 업데이트하고 포지션 조절 시그널을 생성할 수 있습니다.

레짐 수 결정: BIC 기준

레짐을 몇 개로 설정할지는 BIC(Bayesian Information Criterion)로 결정합니다:

# 최적 레짐 수 탐색
bic_scores = {}
for n in range(2, 6):
    hmm = GaussianHMM(
        n_components=n,
        covariance_type="full",
        n_iter=200,
        random_state=42
    )
    hmm.fit(features)
    bic = -2 * hmm.score(features) + n * np.log(len(features))
    bic_scores[n] = bic
    print(f"n={n}: BIC={bic:.0f}")

optimal_n = min(bic_scores, key=bic_scores.get)
print(f"n최적 레짐 수: {optimal_n}")

BIC 값이 가장 낮은 레짐 수가 최적입니다. 대부분의 주식 시장에서는 2~4개 레짐이 적합하며, 3개가 가장 보편적입니다.

주의사항과 한계

  • 과적합 위험: 학습 데이터에 과적합되기 쉬우므로, 반드시 워크포워드 검증을 수행하세요
  • 레짐 라벨링: HMM은 레짐 번호만 부여합니다. Bull/Bear 라벨은 통계적 특성을 보고 수동으로 매핑해야 합니다
  • 전환 지연: HMM은 충분한 데이터가 쌓여야 레짐 전환을 감지합니다. 급격한 시장 변화에는 1~3일 지연이 발생할 수 있습니다
  • 정상성 가정: HMM은 각 레짐 내에서 데이터가 정상(stationary)이라고 가정합니다. 장기적으로 시장 구조가 변하면 재학습이 필요합니다
  • 결합 전략 권장: 레짐 탐지 단독보다 포지션 사이징이나 손절 전략과 결합하면 성과가 크게 개선됩니다

결론

HMM 기반 시장 레짐 탐지는 퀀트 자동매매의 메타 전략입니다. 개별 매매 시그널이 아니라, “지금 어떤 전략을 써야 하는가”를 결정하는 상위 레이어 역할을 합니다. Bull 장에서는 추세 추종, Bear 장에서는 헤지 또는 현금 비중 확대, 횡보 장에서는 평균 회귀 전략을 자동 전환함으로써 시장 환경에 적응하는 로버스트한 시스템을 구축할 수 있습니다.

핵심은 확률 기반 의사결정입니다. 레짐을 이분법적으로 판단하지 않고, 확률 가중치로 포지션을 점진적으로 조절하면 전환기의 손실을 최소화할 수 있습니다.

위로 스크롤
WordPress Appliance - Powered by TurnKey Linux