3.7.4. 전략 3. 볼린저 밴드 활용 변동성 돌파 전략

볼린저 밴드를 활용한 변동성 돌파 전략을 구현합니다. 볼린저 밴드는 가격 변동성을 측정하는 지표입니다. 밴드 상단을 돌파할 때 매수하고 하단을 돌파할 때 매도합니다. 이 전략은 추세 추종 전략과 변동성 매매 전략을 결합합니다.

3.7.4.1 전략 로직 설명

볼린저 밴드는 중심선과 상/하단 밴드로 구성됩니다. 중심선은 일반적으로 20일 이동평균선(SMA)을 사용합니다. 상/하단 밴드는 중심선에서 표준편차의 2배만큼 떨어져 있습니다. 가격이 밴드 밖으로 벗어나는 것은 이례적인 변동성을 의미합니다.

변동성 돌파 전략은 다음과 같은 로직으로 작동합니다.

  1. 가격이 볼린저 밴드 상단을 돌파하면 매수 신호로 간주합니다.
  2. 가격이 볼린저 밴드 하단을 돌파하면 매도 신호로 간주합니다.
  3. 매수 후 가격이 하락하여 중심선을 하향 돌파하면 손절합니다.
  4. 매도 후 가격이 상승하여 중심선을 상향 돌파하면 손절합니다.

이 전략은 변동성이 커지는 시점을 포착하여 수익을 얻습니다. 손절매 규칙을 통해 리스크를 관리합니다. 볼린저 밴드 기간, 표준편차 배수, 손절매 기준 등은 최적화할 수 있습니다.

3.7.4.2 파이썬 코드 구현

볼린저 밴드 활용 변동성 돌파 전략을 파이썬으로 구현합니다. Pandas와 TA-Lib 라이브러리를 사용합니다. 업비트 API를 통해 가상화폐 데이터를 가져옵니다. 백테스팅을 통해 전략의 성능을 평가합니다.

1단계: 필요한 라이브러리 임포트

필요한 라이브러리를 임포트합니다. pandas는 데이터 처리를 위한 라이브러리입니다. talib은 볼린저 밴드 계산을 위한 라이브러리입니다. pyupbit은 업비트 API를 사용하기 위한 라이브러리입니다.

import pandas as pd
import talib
import pyupbit

2단계: 데이터 획득 및 볼린저 밴드 계산

업비트 API를 사용하여 가상화폐 데이터를 가져옵니다. pyupbit.get_ohlcv() 함수를 사용합니다. 데이터프레임의 컬럼명을 통일합니다. 볼린저 밴드를 계산합니다. talib.BBANDS() 함수를 사용합니다. 기본 설정값은 기간 20, 표준편차 2배입니다.

# 업비트 API를 통해 데이터 가져오기
df = pyupbit.get_ohlcv("KRW-BTC", interval="minute60", count=500)

# 컬럼명 변경 (필요한 경우)
df.rename(columns={'open': 'Open', 'high': 'High', 'low': 'Low', 'close': 'Close', 'volume': 'Volume'}, inplace=True)

# 볼린저 밴드 계산
df['BB_UPPER'], df['BB_MIDDLE'], df['BB_LOWER'] = talib.BBANDS(df['Close'], timeperiod=20, nbdevup=2, nbdevdn=2, matype=0)

3단계: 매매 신호 생성 함수 정의

볼린저 밴드를 활용하여 매매 신호를 생성하는 함수를 정의합니다. 상단 밴드를 돌파하면 매수 신호를 생성합니다. 하단 밴드를 돌파하면 매도 신호를 생성합니다. 중심선을 기준으로 손절매 신호를 생성합니다.

def generate_bb_signals(df):
    """볼린저 밴드 활용 변동성 돌파 전략 매매 신호 생성

    Args:
        df (pd.DataFrame): OHLCV 데이터프레임, BB_UPPER, BB_MIDDLE, BB_LOWER, Close 컬럼 필요

    Returns:
        pd.DataFrame: 'signal' 컬럼이 추가된 데이터프레임 (1: 매수, -1: 매도, 0: 유지)
    """
    signals = [0] * len(df)
    position = 0  # 0: No position, 1: Long, -1: Short

    for i in range(1, len(df)):
        # 매수 신호 (상단 밴드 돌파 and No Position)
        if df['Close'][i] > df['BB_UPPER'][i] and position == 0:
            signals[i] = 1
            position = 1
        # 매도 신호 (하단 밴드 돌파 and No Position)
        elif df['Close'][i] < df['BB_LOWER'][i] and position == 0:
            signals[i] = -1
            position = -1
        # 손절매 (Long Position and 중심선 하향 돌파)
        elif df['Close'][i] < df['BB_MIDDLE'][i] and position == 1:
            signals[i] = -1
            position = 0
        # 손절매 (Short Position and 중심선 상향 돌파)
        elif df['Close'][i] > df['BB_MIDDLE'][i] and position == -1:
            signals[i] = 1
            position = 0
        else:
            signals[i] = 0

    df['signal'] = signals
    return df

df = generate_bb_signals(df)
print(df[['Close', 'BB_UPPER', 'BB_LOWER', 'signal']].tail())

4단계: 백테스팅 함수 정의

생성된 매매 신호를 기반으로 백테스팅을 수행하는 함수를 정의합니다. 초기 자본, 수수료를 설정합니다. 각 신호에 따라 매수 및 매도 시뮬레이션을 진행합니다. 최종 자산을 계산하여 전략의 수익성을 평가합니다.

“`python
def bb_backtest(df, initial_balance=1000000, fee=0.0005):
“””볼린저 밴드 활용 변동성 돌파 전략 백테스팅

Args:
    df (pd.DataFrame): OHLCV 데이터프레임, Close, signal 컬럼 필요
    initial_balance (float): 초기 자본
    fee (float): 거래 수수료

Returns:
    float: 최종 자산
"""
balance = initial_balance
position = 0  # 0: No position, 1: Long, -1: Short
buy_price = 0

for i in range(1, len(df)):
    if df['signal'][i] == 1 and position == 0:  # 매수 신호 and No Position
        buy_price = df['Close'][i]
        balance *= (1 - fee)
        position = 1
        print(f"{df.index[i]}: Buy at {buy_price}")
    elif df['signal'][i] == -1 and position == 1:  # 매도 신호 and Long Position (손절 or 청산)
        sell_price = df['Close'][i]
        profit = (sell_price - buy_price) / buy_price
        balance += balance * profit * (1 - fee)
        position = 0
        print(f"{df.index[i]}: Sell at {sell_price}, Profit: {profit:.4f}")
    elif df['signal'][i] == -1 and position == 0:  # 매도 신호 and No Position
        buy_price = df['Close'][i]
        balance *= (1 - fee)
        position = -1
        print(f"{df.index[i]}: Short at {buy_price}")
    elif df['signal'][i] == 1 and position == -1:  # 매수 신호 and Short Position (손절 or 청산)
        sell_price = df['Close'][i]
        profit = (buy_price - sell_price) / buy_price
        balance += balance * profit * (1 - fee)
        position = 0
        print(f"{df.index[i]}: Cover at {sell_price}, Profit: {profit:.4f}")

if position != 0:
    last_price = df['Close'][len(df) - 1]
    if position == 1:
        profit = (last_price - buy_price) / buy_price
    else:
        profit = (buy_price - last_price) / buy_price
    balance += balance * profit * (1 - fee)
    print(f"마지막 청산: {last_price}, 수익률: {profit:.4f}")
위로 스크롤