기술적 지표: 스토캐스틱 (Stochastic)
스토캐스틱 오실레이터(Stochastic Oscillator)는 모멘텀 기반의 기술적 분석 지표 중 하나로서, 일정 기간(period) 동안의 최고가와 최저가 범위 내에서 현재 가격이 어느 수준에 위치하는지를 측정함으로써, 시장 내 매수 및 매도 압력을 추정하는 데 활용된다.
스토캐스틱은 두 개의 선으로 구성된다.
- %K: 일정 기간 동안의 최고가와 최저가 범위 내에서 현재 종가의 상대적 위치를 백분율로 나타낸 값
- %D: %K의 평균
%K 값은 다음의 수식으로 계산된다.
\[ \%K = 100 \times \frac{ \mbox{(현재 종가} - \mbox{기간내 최저가)} }{ \mbox{(기간내 최고가 }- \mbox{기간내 최저가)} } \]
%K 값을 계산할 때 '일정 기간 (period)'은 일반적으로 14일을 사용한다.
%D 값은 %K 값의 단순 이동평균(sma, simple moving average)으로 계산하며 보통 3일 이동 평균이 사용된다.
\[ \% D = \% K \mbox{의 평균} \]
%D는 %K의 노이즈를 줄이기 위한 지표로 보면 된다.
보통 %K와 %D가
- 80 이상이면 과매수 상태 → 하락 가능성 증가
- 20 이하이면 과매도 상태 → 반등 가능성 증가
로 판단한다.
위와 같이 계산한 %K와 %D는 가격 변화에 민감하게 반응하여 단기 매매에 적합하지만, 과도한 신호 발생이 있을 수 있다. 따라서 신호를 한번 더 평균을 내는 방법을 사용하기도 하는데 이를 슬로우 스토캐스틱(slow stochastic)이라고 한다. 반면 원래 지표를 패스트 스토캐스틱(fast stochastic)이라고 부르기도 한다.
슬로우 스토캐스틱에서는 %K 값으로 패스트 스토캐스틱의 %D 값을 사용하고, %D 값으로는 새로운 %K 값의 단순 이동평균으로 계산한다. 마찬가지로 보통 3일 이동 평균이 사용된다.
스토캐스틱을 이용한 매매 전략은 대체로 다음과 같은 것들이 있다.
1.골든크로스/데드크로스 전략
- %K가 %D를 상향 돌파: 매수 신호
- %K가 %D를 하향 돌파: 매도 신호
2. 과매수/과매도 전략
- %K와 %D > 80: 과매수로 간주, 매도 신호로 해석
- %K와 %D < 20: 과매도로 간주, 매수 신호로 해석
3. 복합 전략
- %K > 80에서 %K가 %D를 하향 돌파: 매도 신호
- %K < 20에서 %K가 %D를 상향 돌파: 매수 신호
다음은 슬로우 스토캐스틱 기준으로 3번 매매 전략을 이용하여 테슬라 주식을 거래했을 때 매수, 매도 시점을 마커를 주가에 표시한 것이다. 일봉 데이터이며 period=14를 사용했다.
파란색 마커가 매도 신호, 빨간색 마커가 매수 신호이다.
다음은 위 슬로우 스토캐스틱을 이용한 매매전략을 구현한 파이썬 코드다.
import yfinance as yf
import pandas as pd
import matplotlib.pyplot as plt
# 데이터 다운로드
df = yf.download("TSLA", start="2024-01-01", end="2025-07-07")
# Fast Stochastic 계산
low_14 = df['Low'].rolling(window=14).min()
high_14 = df['High'].rolling(window=14).max()
df['%K_fast'] = (df['Close'] - low_14) / (high_14 - low_14) * 100
df['%D_fast'] = df['%K_fast'].rolling(window=3).mean()
# Slow Stochastic 계산
df['%K_slow'] = df['%K_fast'].rolling(window=3).mean()
df['%D_slow'] = df['%K_slow'].rolling(window=3).mean()
# 매수/매도 조건 설정 (%K_slow vs %D_slow)
df['prev_K'] = df['%K_slow'].shift(1)
df['prev_D'] = df['%D_slow'].shift(1)
buy_signal = (df['%K_slow'] < 20) & (df['%K_slow'] > df['%D_slow']) & (df['prev_K'] <= df['prev_D'])
sell_signal = (df['%K_slow'] > 80) & (df['%K_slow'] < df['%D_slow']) & (df['prev_K'] >= df['prev_D'])
buy_dates = df.index[buy_signal]
sell_dates = df.index[sell_signal]
buy_prices = df['Close'][buy_signal]
sell_prices = df['Close'][sell_signal]
# 시각화
plt.figure(figsize=(14, 10))
# 종가 + 마커
plt.subplot(2, 1, 1)
plt.plot(df.index, df['Close'], label='TSLA Close', color='black')
plt.scatter(buy_dates, buy_prices, marker='^', color='red', label='Buy Signal (Slow Stoch)', s=100)
plt.scatter(sell_dates, sell_prices, marker='v', color='blue', label='Sell Signal (Slow Stoch)', s=100)
plt.title('Tesla (TSLA) Closing Price with Slow Stochastic Buy/Sell Signals')
plt.ylabel('Price ($)')
plt.grid(True)
plt.legend()
# Slow Stochastic 지표
plt.subplot(2, 1, 2)
plt.plot(df.index, df['%K_slow'], label='%K (Slow)', color='blue')
plt.plot(df.index, df['%D_slow'], label='%D (Slow)', color='orange')
plt.axhline(80, color='red', linestyle='--', alpha=0.5, label='Overbought (80)')
plt.axhline(20, color='green', linestyle='--', alpha=0.5, label='Oversold (20)')
plt.title('Slow Stochastic Oscillator (%K_slow and %D_slow)')
plt.ylabel('Oscillator Value')
plt.grid(True)
plt.legend()
plt.tight_layout()
plt.show()