볼린저 밴드 자동매매 전략

볼린저 밴드란

볼린저 밴드(Bollinger Bands)는 1980년대 존 볼린저가 개발한 기술적 지표로, 이동평균선을 중심으로 표준편차 기반의 상·하한 밴드를 그려 가격의 상대적 위치와 변동성을 동시에 파악합니다. 전 세계 트레이더들이 가장 많이 사용하는 지표 중 하나이며, 자동매매 시스템에서도 핵심 신호 생성기로 활용됩니다.

볼린저 밴드는 세 개의 선으로 구성됩니다:

  • 중심선(Middle Band): N일 단순 이동평균(SMA)
  • 상단 밴드(Upper Band): 중심선 + K × 표준편차
  • 하단 밴드(Lower Band): 중심선 − K × 표준편차

기본 설정은 N=20, K=2입니다. 이 설정에서 가격의 약 95%가 밴드 안에 위치합니다.

볼린저 밴드의 핵심 매매 신호

볼린저 밴드에서 추출할 수 있는 주요 매매 신호는 네 가지입니다.

1. 밴드 터치 반전(Mean Reversion)

가격이 하단 밴드에 닿으면 매수, 상단 밴드에 닿으면 매도하는 평균 회귀 전략입니다. 횡보장에서 높은 승률을 보이지만, 강한 추세장에서는 역추세 매매가 되어 위험합니다.

2. 볼린저 스퀴즈(Squeeze)

밴드 폭이 극도로 좁아지는 구간은 변동성 축소를 의미하며, 곧 큰 움직임이 올 신호입니다. 변동성 돌파 전략과 결합하면 강력한 브레이크아웃 진입점을 포착할 수 있습니다.

3. 밴드 워킹(Walking the Bands)

강한 추세에서 가격이 상단(또는 하단) 밴드를 따라 이동하는 현상입니다. 이때는 반전 매매가 아닌 추세 추종이 올바른 접근입니다.

4. %B 지표와 밴드 폭(Bandwidth)

%B는 현재 가격이 밴드 내 어디에 위치하는지를 0~1 사이 값으로 정량화합니다. 밴드 폭(Bandwidth)은 변동성의 절대적 크기를 측정합니다.

Python 구현: 볼린저 밴드 자동매매

import numpy as np
import pandas as pd

class BollingerBandStrategy:
    """볼린저 밴드 기반 자동매매 전략"""
    
    def __init__(self, period=20, num_std=2, squeeze_threshold=0.04):
        self.period = period
        self.num_std = num_std
        self.squeeze_threshold = squeeze_threshold
    
    def calculate_bands(self, prices: pd.Series) -> pd.DataFrame:
        """볼린저 밴드 계산"""
        df = pd.DataFrame({'close': prices})
        df['sma'] = prices.rolling(self.period).mean()
        df['std'] = prices.rolling(self.period).std()
        df['upper'] = df['sma'] + self.num_std * df['std']
        df['lower'] = df['sma'] - self.num_std * df['std']
        
        # %B: 밴드 내 위치 (0=하단, 1=상단)
        df['pct_b'] = (prices - df['lower']) / (df['upper'] - df['lower'])
        
        # 밴드 폭: 변동성 지표
        df['bandwidth'] = (df['upper'] - df['lower']) / df['sma']
        
        return df
    
    def detect_squeeze(self, df: pd.DataFrame) -> pd.Series:
        """볼린저 스퀴즈 감지"""
        bw_min = df['bandwidth'].rolling(120).min()
        return df['bandwidth'] <= bw_min * (1 + self.squeeze_threshold)
    
    def generate_signals(self, prices: pd.Series) -> pd.DataFrame:
        """매매 신호 생성"""
        df = self.calculate_bands(prices)
        df['squeeze'] = self.detect_squeeze(df)
        df['signal'] = 'HOLD'
        
        for i in range(1, len(df)):
            if pd.isna(df.iloc[i]['sma']):
                continue
            
            pct_b = df.iloc[i]['pct_b']
            prev_pct_b = df.iloc[i-1]['pct_b']
            squeeze = df.iloc[i]['squeeze']
            
            # 스퀴즈 브레이크아웃
            if squeeze and pct_b > 1.0:
                df.iloc[i, df.columns.get_loc('signal')] = 'BUY'
            elif squeeze and pct_b < 0.0:
                df.iloc[i, df.columns.get_loc('signal')] = 'SELL'
            
            # 평균 회귀 (비스퀴즈 구간)
            elif not squeeze and prev_pct_b > 0 and pct_b <= 0:
                df.iloc[i, df.columns.get_loc('signal')] = 'BUY'
            elif not squeeze and prev_pct_b < 1 and pct_b >= 1:
                df.iloc[i, df.columns.get_loc('signal')] = 'SELL'
        
        return df

볼린저 밴드 + RSI 복합 전략

볼린저 밴드 단독 사용보다 RSI(상대강도지수)를 결합하면 거짓 신호를 크게 줄일 수 있습니다. 볼린저 하단 터치 + RSI 30 이하일 때만 매수하는 방식입니다.

def rsi(prices, period=14):
    """RSI 계산"""
    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))

def bollinger_rsi_signal(prices, bb_period=20, rsi_period=14):
    """볼린저 밴드 + RSI 복합 신호"""
    strategy = BollingerBandStrategy(period=bb_period)
    df = strategy.calculate_bands(prices)
    df['rsi'] = rsi(prices, rsi_period)
    
    signals = []
    for i in range(len(df)):
        if pd.isna(df.iloc[i]['rsi']) or pd.isna(df.iloc[i]['sma']):
            signals.append('HOLD')
            continue
        
        pct_b = df.iloc[i]['pct_b']
        rsi_val = df.iloc[i]['rsi']
        
        # 하단 밴드 + RSI 과매도 → 강한 매수
        if pct_b <= 0 and rsi_val < 30:
            signals.append('STRONG_BUY')
        # 상단 밴드 + RSI 과매수 → 강한 매도
        elif pct_b >= 1 and rsi_val > 70:
            signals.append('STRONG_SELL')
        else:
            signals.append('HOLD')
    
    df['combo_signal'] = signals
    return df

이 복합 전략은 두 가지 독립적 지표가 동시에 같은 방향을 가리킬 때만 진입하므로, 단일 지표 대비 승률이 높아집니다.

파라미터 최적화 가이드

파라미터 기본값 단기 매매 중장기 매매
이동평균 기간(N) 20 10~15 30~50
표준편차 배수(K) 2.0 1.5~2.0 2.0~2.5
RSI 기간 14 7~10 14~21
스퀴즈 룩백 120 60~90 120~200

파라미터 최적화 시 백테스트 과적합에 주의하세요. 워크포워드 분석(Walk-Forward Analysis)을 적용해 인샘플과 아웃오브샘플을 분리하는 것이 필수입니다.

시장 상황별 전략 전환

볼린저 밴드의 가장 큰 함정은 시장 상황에 따라 다른 전략이 필요하다는 것입니다:

  • 횡보장(밴드 폭 보통): 평균 회귀 전략 → 밴드 터치에서 반전 매매
  • 추세장(밴드 워킹): 추세 추종 → 밴드를 따라가는 포지션 유지
  • 스퀴즈 구간: 브레이크아웃 대기 → 밴드 이탈 방향으로 진입

자동매매 봇에서는 밴드 폭(Bandwidth)으로 현재 시장 상태를 자동 분류하고, 상태에 맞는 전략을 동적으로 전환하는 로직이 중요합니다. 리스크 관리와 함께 각 상태별 손절·익절 기준도 달리 설정해야 합니다.

실전 적용 시 주의사항

  • 후행 지표: 볼린저 밴드는 과거 데이터 기반이므로 급격한 뉴스 이벤트에는 대응이 늦습니다. 뉴스 필터를 병행하세요.
  • 거래량 확인: 밴드 이탈이 거래량 증가를 동반해야 유의미한 신호입니다. 저거래량 이탈은 거짓 신호일 확률이 높습니다.
  • 다중 타임프레임: 일봉 볼린저 밴드와 4시간봉 볼린저 밴드가 같은 방향을 가리킬 때 신뢰도가 높아집니다.
  • 샤프 비율로 성과 측정: 볼린저 밴드 전략의 리스크 대비 수익을 정량화해 다른 전략과 비교하세요.

마무리

볼린저 밴드는 변동성과 가격 위치를 동시에 포착하는 직관적이면서도 강력한 도구입니다. 평균 회귀, 브레이크아웃, 추세 추종까지 다양한 전략에 활용 가능하며, RSI 같은 보조 지표와 결합하면 신호 품질이 크게 향상됩니다. 시장 상태 자동 분류와 전략 전환 로직을 추가하면, 어떤 시장 환경에서도 안정적인 자동매매 시스템을 구축할 수 있습니다.

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