칼만 필터 자동매매 전략 구현

칼만 필터란 무엇인가

칼만 필터(Kalman Filter)는 노이즈가 포함된 시계열 데이터에서 실제 상태(hidden state)를 추정하는 최적 필터링 알고리즘입니다. 1960년 루돌프 칼만이 발표한 이 알고리즘은 항공·우주 분야에서 시작해 현재는 퀀트 투자와 자동매매 분야에서도 핵심 도구로 자리 잡았습니다.

주식·암호화폐 가격은 랜덤 노이즈가 심합니다. 단순 이동평균(SMA)이나 지수 이동평균(EMA)은 과거 데이터에 고정된 가중치를 부여하지만, 칼만 필터는 시장 상황에 따라 가중치를 동적으로 조절합니다. 이것이 자동매매에서 칼만 필터가 주목받는 이유입니다.

칼만 필터의 핵심 원리

칼만 필터는 두 단계를 반복합니다:

  • 예측(Predict): 이전 상태와 모델을 기반으로 다음 상태를 예측
  • 업데이트(Update): 실제 관측값과 예측값의 차이(이노베이션)를 반영해 추정값 보정

수식으로 표현하면 다음과 같습니다:

// 예측 단계
x̂(k|k-1) = F · x̂(k-1|k-1) + B · u(k)
P(k|k-1)  = F · P(k-1|k-1) · Fᵀ + Q

// 업데이트 단계
K(k) = P(k|k-1) · Hᵀ · (H · P(k|k-1) · Hᵀ + R)⁻¹
x̂(k|k) = x̂(k|k-1) + K(k) · (z(k) - H · x̂(k|k-1))
P(k|k) = (I - K(k) · H) · P(k|k-1)

여기서 K(k)는 칼만 이득(Kalman Gain)으로, 관측값을 얼마나 신뢰할지 자동으로 결정합니다. 노이즈가 크면 예측값을 더 신뢰하고, 노이즈가 작으면 관측값을 더 반영합니다.

자동매매에서 칼만 필터 활용법

칼만 필터를 자동매매 시스템에 적용하는 대표적인 방법은 세 가지입니다.

1. 동적 추세 추정(Dynamic Trend Estimation)

가격의 숨겨진 추세를 실시간으로 추정합니다. SMA보다 지연(lag)이 적고, 급격한 변동에도 빠르게 적응합니다. 칼만 필터 추정값이 상승 추세를 보이면 매수, 하락 추세면 매도하는 전략을 구현할 수 있습니다.

2. 페어 트레이딩 스프레드 추정

두 종목 간의 페어 트레이딩 헤지 비율을 칼만 필터로 동적 추정합니다. 고정 회귀 계수 대신 시간에 따라 변하는 베타를 추적해 스프레드 계산의 정확도를 높입니다.

3. 변동성 필터링

변동성 돌파 전략에서 칼만 필터로 노이즈를 제거한 변동성을 추정하면 거짓 신호(false signal)를 줄일 수 있습니다.

Python 구현: 칼만 필터 자동매매

아래는 칼만 필터를 이용한 추세 추종 자동매매의 핵심 구현입니다.

import numpy as np

class KalmanTrendFilter:
    """칼만 필터 기반 추세 추정기"""
    
    def __init__(self, q=1e-5, r=1e-2):
        # 상태: [price, trend]
        self.x = np.array([0.0, 0.0])  # 초기 상태
        self.P = np.eye(2) * 1000       # 초기 공분산 (불확실성 높게)
        self.F = np.array([[1, 1],       # 상태 전이 행렬
                           [0, 1]])
        self.H = np.array([[1, 0]])      # 관측 행렬
        self.Q = np.array([[q, 0],       # 프로세스 노이즈
                           [0, q]])
        self.R = np.array([[r]])         # 관측 노이즈
    
    def update(self, price):
        # 예측
        x_pred = self.F @ self.x
        P_pred = self.F @ self.P @ self.F.T + self.Q
        
        # 칼만 이득
        S = self.H @ P_pred @ self.H.T + self.R
        K = P_pred @ self.H.T @ np.linalg.inv(S)
        
        # 업데이트
        z = np.array([price])
        innovation = z - self.H @ x_pred
        self.x = x_pred + K @ innovation
        self.P = (np.eye(2) - K @ self.H) @ P_pred
        
        return self.x[0], self.x[1]  # 추정가격, 추세

def run_strategy(prices, q=1e-5, r=1e-2):
    """칼만 필터 추세 추종 전략 실행"""
    kf = KalmanTrendFilter(q=q, r=r)
    signals = []
    
    for price in prices:
        est_price, trend = kf.update(price)
        
        if trend > 0.001:
            signals.append("BUY")
        elif trend < -0.001:
            signals.append("SELL")
        else:
            signals.append("HOLD")
    
    return signals

파라미터 튜닝 전략

칼만 필터 성능은 Q(프로세스 노이즈)와 R(관측 노이즈) 설정에 크게 좌우됩니다.

파라미터 값이 클 때 값이 작을 때 적합한 시장
Q (프로세스) 빠른 적응, 노이즈 민감 부드러운 추정, 지연 증가 Q↑: 급변 시장 / Q↓: 안정 시장
R (관측) 관측값 불신, 예측 의존 관측값 신뢰, 빠른 반응 R↑: 고변동성 / R↓: 저변동성

실전에서는 백테스트 과적합 방지 원칙을 지키면서 롤링 윈도우 최적화를 적용합니다. Q와 R을 최근 N일 데이터에서 최대 샤프 비율을 달성하는 값으로 주기적으로 재조정하는 방식이 일반적입니다.

칼만 필터 vs 이동평균 비교

항목 칼만 필터 이동평균(SMA/EMA)
적응성 시장 상황에 동적 적응 고정 파라미터
지연(Lag) 최소 윈도우 크기에 비례
노이즈 필터링 최적(베이지안) 단순 평균
구현 난이도 중간~높음 낮음
추세 추출 상태 벡터로 직접 추출 크로스오버 간접 판단

실전 적용 시 주의사항

  • 초기 수렴 기간: 칼만 필터는 초기 몇십 개 데이터 포인트 동안 불안정합니다. 이 구간에서는 매매 신호를 무시해야 합니다.
  • 비선형 시장: 기본 칼만 필터는 선형 모델입니다. 극단적 변동(블랙 스완)에는 Extended Kalman Filter(EKF)나 Unscented Kalman Filter(UKF)를 고려하세요.
  • 리스크 관리 병행: 칼만 필터는 신호 생성 도구일 뿐, 리스크 관리와 반드시 병행해야 합니다. 손절선·포지션 사이징은 별도로 설정하세요.
  • 거래 비용 반영: 칼만 필터의 빠른 반응은 잦은 매매로 이어질 수 있습니다. 최소 신호 임계값을 설정해 과매매(overtrading)를 방지하세요.

마무리

칼만 필터는 노이즈 제거와 동적 추세 추정에서 전통적 지표를 크게 능가합니다. 특히 페어 트레이딩의 헤지 비율 추정, 변동성 필터링, 추세 추종 전략에서 강력한 성능을 보여줍니다. Python의 NumPy만으로도 충분히 구현 가능하므로, 자동매매 시스템에 칼만 필터를 도입해 매매 신호의 품질을 한 단계 높여 보세요.

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