캘트너 밴드의 개념과 유래
캘트너 밴드(Keltner Band)는 주가의 변동성과 추세를 파악하는데 사용되는 기술적 지표 중 하나이다. 1960년대에 Chester W. Keltner가 개발한 이 지표는 중심선과 상하단 밴드로 구성되며, 주가의 움직임을 시각적으로 표현한다.
캘트너 밴드의 중심선은 일반적으로 20일 이동평균선을 사용하며, 상단 밴드와 하단 밴드는 중심선에서 평균 실제 범위(Average True Range, ATR)의 일정 배수만큼 떨어진 곳에 위치한다. ATR은 주가의 변동성을 나타내는 지표로, 주로 14일을 기준으로 계산된다.
예를 들어, 주가가 상승 추세에 있고 상단 밴드를 돌파할 경우, 강한 매수 신호로 해석할 수 있다. 반대로 주가가 하단 밴드를 하향 돌파한다면, 매도 신호로 판단할 수 있다.
캘트너 밴드를 활용한 매매 전략
캘트너 밴드를 활용한 대표적인 매매 전략은 다음과 같다:
- 추세 추종 전략: 주가가 상단 밴드 위에 위치할 때 매수하고, 하단 밴드 아래로 내려갈 때 매도하는 전략이다. 이는 강한 추세를 따라 매매하는 방식으로, 추세가 지속되는 한 수익을 기대할 수 있다.
- 역추세 전략: 주가가 상단 밴드에 도달하면 매도하고, 하단 밴드에 도달하면 매수하는 전략이다. 이는 주가가 밴드 상단이나 하단에 도달했을 때 과매수 또는 과매도 상태일 가능성이 높다는 가정에 기반한다.
- 범위 내 매매 전략: 주가가 캘트너 밴드의 상단과 하단 사이에서 움직일 때, 상단에서 매도하고 하단에서 매수하는 전략이다. 이는 주가의 변동성이 크지 않은 횡보장에서 효과적일 수 있다.
실제 트레이딩에서는 캘트너 밴드와 함께 다른 기술적 지표나 기본적 분석을 함께 사용하여 매매 신호의 정확성을 높이는 것이 좋다. 또한 위험 관리 차원에서 적절한 손절매와 이익 실현 기준을 설정하는 것도 중요하다.
파이썬을 활용한 캘트너 밴드 백테스팅
이제 파이썬을 사용하여 캘트너 밴드 매매 전략을 백테스팅해보자. 이를 위해 다음 라이브러리를 사용할 것이다:
pandas
: 데이터 조작 및 분석을 위한 라이브러리numpy
: 수치 계산을 위한 라이브러리matplotlib
: 데이터 시각화를 위한 라이브러리FinanceDataReader
: 주가 데이터를 가져오기 위한 라이브러리
먼저 가상환경을 활성화하고 필요한 라이브러리를 설치한다.
source venv/bin/activate
pip install pandas numpy matplotlib FinanceDataReader
FinanceDataReader를 설치할 때 종속 모듈도 함께 설치되므로 별도의 설치 과정이 필요하지 않다.
다음으로 캘트너 밴드를 계산하고 매매 신호를 생성하는 코드를 작성해보자.
import FinanceDataReader as fdr
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# 데이터 가져오기
symbol = "VOO"
start_date = "1900-01-01"
end_date = "2023-05-01"
try:
data = fdr.DataReader(symbol, start_date, end_date)
except Exception as e:
print(f"Error occurred while fetching data: {e}")
exit(1)
# ATR 계산 함수
def get_atr(data, window):
high_low = data['High'] - data['Low']
high_close = np.abs(data['High'] - data['Close'].shift())
low_close = np.abs(data['Low'] - data['Close'].shift())
ranges = pd.concat([high_low, high_close, low_close], axis=1)
true_range = np.max(ranges, axis=1)
atr = true_range.rolling(window).mean()
return atr
# 캘트너 밴드 계산
def get_keltner_bands(data, window=20, atr_window=10, multiplier=2):
ema = data['Close'].ewm(span=window, adjust=False).mean()
atr = get_atr(data, atr_window)
upper_band = ema + multiplier * atr
lower_band = ema - multiplier * atr
return ema, upper_band, lower_band
# 매매 신호 생성 함수
def get_signals(data, upper_band, lower_band):
signals = pd.DataFrame(index=data.index)
signals['signal'] = 0
signals['signal'][data['Close'] > upper_band] = -1
signals['signal'][data['Close'] < lower_band] = 1
signals['positions'] = signals['signal'].diff()
return signals
# 캘트너 밴드 계산
ema, upper_band, lower_band = get_keltner_bands(data)
# 매매 신호 생성
signals = get_signals(data, upper_band, lower_band)
# 백테스팅
initial_capital = 10000
positions = pd.DataFrame(index=signals.index).fillna(0.0)
positions['VOO'] = 100 * signals['signal']
portfolio = positions.multiply(data['Adj Close'], axis=0)
pos_diff = positions.diff()
portfolio['holdings'] = (positions.multiply(data['Adj Close'], axis=0)).sum(axis=1)
portfolio['cash'] = initial_capital - (pos_diff.multiply(data['Adj Close'], axis=0)).sum(axis=1).cumsum()
portfolio['total'] = portfolio['cash'] + portfolio['holdings']
portfolio['returns'] = portfolio['total'].pct_change()
# 결과 출력
print(f"Final portfolio value: ${portfolio['total'][-1]:,.2f}")
print(f"Total returns: {100 * (portfolio['total'][-1] / initial_capital - 1):.2f}%")
# 시각화
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(15, 10), gridspec_kw={'height_ratios': [3, 1]})
ax1.plot(data['Close'], label='Close Price')
ax1.plot(ema, label='EMA')
ax1.plot(upper_band, 'g--', label='Upper Band')
ax1.plot(lower_band, 'r--', label='Lower Band')
ax1.legend(loc='upper left')
ax1.set_title(f'{symbol} Keltner Bands')
ax2.plot(portfolio['total'], label='Portfolio Value')
ax2.legend(loc='upper left')
ax2.set_title('Portfolio Performance')
plt.tight_layout()
plt.show()
위 코드에서는 먼저 FinanceDataReader를 사용하여 VOO ETF의 전체 기간 주가 데이터를 가져온다. 이때 start_date
를 가능한 한 오래전 날짜로 설정하여 모든 데이터를 가져올 수 있도록 한다.
다음으로 get_atr
함수를 정의하여 ATR을 계산하고, get_keltner_bands
함수를 사용하여 캘트너 밴드의 중심선, 상단 밴드, 하단 밴드를 계산한다.
get_signals
함수는 주가가 상단 밴드를 돌파할 때 매도 신호(-1), 하단 밴드를 돌파할 때 매수 신호(1)를 생성한다.
백테스팅을 위해 초기 자본금을 10,000달러로 설정하고, 생성된 매매 신호를 바탕으로 포트폴리오 가치를 계산한다. 최종적으로 총 수익률과 포트폴리오 가치를 출력한다.
마지막으로 matplotlib
을 사용하여 주가, 캘트너 밴드, 포트폴리오 가치를 시각화한다.
코드 실행 중 발생할 수 있는 오류를 처리하기 위해 try-except
문을 사용하였다. 데이터를 가져오는 과정에서 오류가 발생하면 에러 메시지를 출력하고 프로그램을 종료한다.