마켓 레짐 감지 자동매매 전략

마켓 레짐이란 무엇인가

금융 시장은 항상 같은 방식으로 움직이지 않습니다. 상승 추세(Bull), 하락 추세(Bear), 횡보(Sideways) 등 서로 다른 시장 국면(Market Regime)이 존재하며, 각 국면에서 최적의 전략은 완전히 다릅니다. 추세 추종 전략은 횡보장에서 손실을 내고, 평균 회귀 전략은 강한 추세장에서 큰 손실을 입습니다.

마켓 레짐 감지(Market Regime Detection)란 현재 시장이 어떤 국면에 있는지 통계적으로 판별하는 기법입니다. 이를 자동매매 시스템에 결합하면 국면별로 전략을 전환하거나 포지션 크기를 조절할 수 있습니다.

HMM(은닉 마르코프 모델) 기반 레짐 감지

Hidden Markov Model(HMM)은 마켓 레짐 감지에 가장 널리 쓰이는 통계 모델입니다. 시장의 관측 가능한 수익률 뒤에 ‘은닉된’ 상태(레짐)가 존재한다고 가정하고, 각 레짐의 수익률 분포와 전이 확률을 추정합니다.

HMM의 핵심 구성 요소

  • 은닉 상태(Hidden States): 관측할 수 없는 시장 국면 (예: 저변동 상승, 고변동 하락)
  • 관측값(Observations): 실제 수익률 데이터
  • 전이 확률(Transition Probability): 한 레짐에서 다른 레짐으로 전환될 확률
  • 방출 확률(Emission Probability): 각 레짐에서 특정 수익률이 나올 확률 분포

파이썬 HMM 레짐 감지 구현

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

# 데이터 수집
data = yf.download("SPY", start="2020-01-01", end="2025-12-31")
returns = data['Close'].pct_change().dropna()

# 특성 행렬 구성: 수익률 + 변동성
features = pd.DataFrame({
    'returns': returns,
    'volatility': returns.rolling(20).std()
}).dropna()

# 2-상태 가우시안 HMM 학습
model = GaussianHMM(
    n_components=2,
    covariance_type="full",
    n_iter=1000,
    random_state=42
)
model.fit(features.values)

# 레짐 예측
regimes = model.predict(features.values)
features['regime'] = regimes

# 각 레짐별 통계
for i in range(2):
    mask = features['regime'] == i
    mean_ret = features.loc[mask, 'returns'].mean() * 252
    vol = features.loc[mask, 'returns'].std() * np.sqrt(252)
    print(f"Regime {i}: 연간수익률={mean_ret:.2%}, 연간변동성={vol:.2%}")

레짐별 전략 전환 시스템

레짐을 감지한 후 각 국면에 맞는 전략을 자동으로 전환하는 것이 핵심입니다. 아래는 레짐별 전략 매핑 예시입니다.

레짐 특성 적합 전략 포지션 크기
저변동 상승 낮은 변동성, 양의 수익률 추세 추종, 모멘텀 100%
고변동 하락 높은 변동성, 음의 수익률 숏 전략, 헤지, 현금 보유 30~50%
횡보 중간 변동성, 평균 회귀 평균 회귀, 박스권 매매 50~70%

레짐 전환 자동매매 코드

class RegimeSwitchingStrategy:
    """레짐 전환 기반 자동매매 전략"""
    
    def __init__(self, hmm_model, lookback=60):
        self.model = hmm_model
        self.lookback = lookback
        self.strategies = {
            0: self.momentum_strategy,  # 저변동 상승
            1: self.defensive_strategy,  # 고변동 하락
        }
        self.position_scales = {0: 1.0, 1: 0.3}
    
    def detect_regime(self, recent_data):
        """최근 데이터로 현재 레짐 판별"""
        features = self._compute_features(recent_data)
        regime = self.model.predict(features)[-1]
        proba = self.model.predict_proba(features)[-1]
        return regime, proba
    
    def momentum_strategy(self, data):
        """추세 추종: 20일 이평선 돌파"""
        sma20 = data['close'].rolling(20).mean()
        if data['close'].iloc[-1] > sma20.iloc[-1]:
            return 'BUY'
        return 'SELL'
    
    def defensive_strategy(self, data):
        """방어적: RSI 과매도 반등만 진입"""
        rsi = self._compute_rsi(data['close'], 14)
        if rsi.iloc[-1] < 30:
            return 'BUY'
        elif rsi.iloc[-1] > 70:
            return 'SELL'
        return 'HOLD'
    
    def generate_signal(self, data):
        """레짐 감지 → 전략 선택 → 신호 생성"""
        regime, proba = self.detect_regime(data)
        confidence = proba[regime]
        
        # 레짐 확신도가 낮으면 포지션 축소
        if confidence < 0.7:
            scale = self.position_scales[regime] * 0.5
        else:
            scale = self.position_scales[regime]
        
        strategy_fn = self.strategies[regime]
        signal = strategy_fn(data)
        
        return {
            'signal': signal,
            'regime': regime,
            'confidence': confidence,
            'position_scale': scale
        }
    
    def _compute_features(self, data):
        returns = data['close'].pct_change().dropna()
        vol = returns.rolling(20).std()
        features = pd.DataFrame({
            'returns': returns, 'volatility': vol
        }).dropna()
        return features.values
    
    def _compute_rsi(self, prices, period=14):
        delta = prices.diff()
        gain = delta.where(delta > 0, 0).rolling(period).mean()
        loss = (-delta.where(delta < 0, 0)).rolling(period).mean()
        rs = gain / loss
        return 100 - (100 / (1 + rs))

레짐 감지 고도화 기법

기본 HMM 외에도 레짐 감지 정확도를 높이는 다양한 기법이 있습니다.

1. 다중 특성 활용

수익률과 변동성 외에 거래량, VIX, 금리 스프레드 등을 추가하면 레짐 분류 정확도가 향상됩니다.

# 다중 특성 HMM
features = pd.DataFrame({
    'returns': returns,
    'volatility': returns.rolling(20).std(),
    'volume_change': data['Volume'].pct_change().rolling(10).mean(),
    'high_low_range': ((data['High'] - data['Low']) / data['Close']).rolling(10).mean()
}).dropna()

model_multi = GaussianHMM(n_components=3, covariance_type="full", n_iter=1000)
model_multi.fit(features.values)

2. 온라인 학습과 적응

시장 구조는 시간이 지나면서 변합니다. 정기적으로 HMM을 재학습하여 최신 시장 패턴에 적응시켜야 합니다.

class AdaptiveRegimeDetector:
    """주기적 재학습으로 시장 변화에 적응"""
    
    def __init__(self, n_regimes=2, retrain_days=60):
        self.n_regimes = n_regimes
        self.retrain_days = retrain_days
        self.model = None
        self.last_train_date = None
    
    def fit_or_update(self, data, current_date):
        needs_retrain = (
            self.model is None or
            (current_date - self.last_train_date).days >= self.retrain_days
        )
        if needs_retrain:
            features = self._prepare_features(data)
            self.model = GaussianHMM(
                n_components=self.n_regimes,
                covariance_type="full",
                n_iter=500
            )
            self.model.fit(features)
            self.last_train_date = current_date
        return self.model

3. 레짐 전환 필터링

잦은 레짐 전환은 과도한 매매를 유발합니다. 최소 유지 기간이나 확률 임계값을 설정하여 변동성 기반 포트폴리오 관리와 결합하면 안정적인 시스템을 구축할 수 있습니다.

def filter_regime_changes(regimes, probas, min_duration=5, min_confidence=0.75):
    """레짐 전환 노이즈 필터링"""
    filtered = regimes.copy()
    current_regime = regimes[0]
    days_in_regime = 0
    
    for i in range(len(regimes)):
        if regimes[i] != current_regime:
            # 새 레짐 확률이 충분히 높고, 기존 레짐 유지 기간이 최소 이상일 때만 전환
            if probas[i][regimes[i]] >= min_confidence and days_in_regime >= min_duration:
                current_regime = regimes[i]
                days_in_regime = 0
            else:
                filtered[i] = current_regime
        days_in_regime += 1
    
    return filtered

백테스트: 레짐 전환 vs 단일 전략

레짐 전환 전략의 효과를 검증하기 위해 단일 전략 대비 성과를 비교해보겠습니다.

def backtest_regime_switching(data, model, initial_capital=10000):
    """레짐 전환 전략 백테스트"""
    features = compute_features(data)
    regimes = model.predict(features)
    probas = model.predict_proba(features)
    
    # 레짐 필터링 적용
    regimes = filter_regime_changes(regimes, probas)
    
    capital = initial_capital
    position = 0
    results = []
    
    for i in range(1, len(data)):
        regime = regimes[i]
        price = data['close'].iloc[i]
        prev_price = data['close'].iloc[i-1]
        ret = (price - prev_price) / prev_price
        
        # 레짐별 포지션 비율
        target_exposure = {0: 1.0, 1: -0.3, 2: 0.0}
        exposure = target_exposure.get(regime, 0)
        
        # 수익 계산
        pnl = capital * exposure * ret
        capital += pnl
        results.append({
            'date': data.index[i],
            'capital': capital,
            'regime': regime,
            'exposure': exposure
        })
    
    results_df = pd.DataFrame(results)
    total_return = (capital - initial_capital) / initial_capital
    sharpe = (results_df['capital'].pct_change().mean() / 
              results_df['capital'].pct_change().std()) * np.sqrt(252)
    
    print(f"총 수익률: {total_return:.2%}")
    print(f"샤프 비율: {sharpe:.2f}")
    print(f"최대 낙폭: {compute_max_drawdown(results_df['capital']):.2%}")
    
    return results_df

def compute_max_drawdown(equity_curve):
    peak = equity_curve.expanding().max()
    drawdown = (equity_curve - peak) / peak
    return drawdown.min()

실전 적용 시 주의사항

마켓 레짐 감지를 실전에 적용할 때 반드시 고려해야 할 사항들입니다.

  • 과적합 위험: HMM의 상태 수를 너무 많이 설정하면 과적합됩니다. 보통 2~3개가 적절합니다.
  • 레짐 전환 지연: HMM은 후행 지표입니다. 레짐 전환 신호가 실제 전환보다 늦게 나올 수 있으므로, 전환 초기 손실을 감수할 준비가 필요합니다.
  • 거래 비용: 레짐 전환 시 전략 변경에 따른 포지션 재조정 비용을 반드시 포함하여 백테스트해야 합니다.
  • 샘플 외 검증: 반드시 워크포워드 분석으로 샘플 외 성과를 검증하세요.
  • 다중 자산 적용: 단일 자산보다 여러 자산의 레짐을 동시에 추적하면 더 강건한 시스템을 구축할 수 있습니다.

마무리

마켓 레짐 감지는 자동매매 시스템의 적응력을 크게 높여주는 핵심 기법입니다. HMM을 기반으로 시장 국면을 분류하고, 각 국면에 맞는 전략을 자동 전환함으로써 단일 전략의 한계를 극복할 수 있습니다. 핵심은 과적합을 피하면서도 충분한 적응력을 갖추는 균형을 찾는 것입니다. 레짐 전환 필터링과 주기적 재학습을 결합하면 실전에서도 안정적으로 작동하는 시스템을 구축할 수 있습니다.

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