RSI, 볼린저 밴드를 활용한 투자 전략 (EMA, finterstellar 라이브러리 사용)
RSI (Relative Strength Index, 상대 강도 지수)
주식, 외환, 암호화폐 등 금융 상품의 가격이 과매도 또는 과매수 상태에 있는지를 판단하는 지표로 사용
- RSI ≥ 70: 과매수 상태를 나타내며, 가격이 고평가될 가능성 ↑. 이때 매도 신호로 해석
- RSI ≤ 30: 과매도 상태를 나타내며, 가격이 저평가될 가능성 ↑ . 이때 매수 신호로 해석
RSI 계산 과정
- 변화량 계산: 특정 주기의 종가 변화를 구해 상승폭과 하락폭을 구한다.
- AU (Average Up): 일정 기간 동안의 평균 상승폭.
- DU (Average Down): 일정 기간 동안의 평균 하락폭.
- RSI 계산:
import FinanceDataReader as fdr
import matplotlib.pyplot as plt
import seaborn as sns
# 삼성전자 종가 데이터 불러오기
df = fdr.DataReader('005930') # 티커 005930은 삼성전자
# RSI 계산 함수 정의
def make_rsi(close, period=14):
delta = close.diff() # 종가 변화량 계산
gain = delta.where(delta >= 0, 0) # 양수일 경우 상승폭으로 사용
loss = -delta.where(delta < 0, 0) # 음수일 경우 하락폭으로 사용
# 14일 평균 상승폭과 하락폭 계산
avg_gain = gain.rolling(window=period).mean()
avg_loss = loss.rolling(window=period).mean()
# RSI 계산
rsi = avg_gain / (avg_gain + avg_loss) * 100
return rsi
# make_rsi 함수를 사용하여 RSI 계산
df['RSI'] = make_rsi(df['Close'])
# 매매 상태 결정 함수 정의
def determine_state(x):
if x <= 30:
return 'Buy' # RSI가 30 이하일 때 매수 신호
elif x >= 70:
return 'Sell' # RSI가 70 이상일 때 매도 신호
else:
return 'Hold' # 그 외에는 보유 상태
# RSI 값을 기반으로 상태(State) 열 생성
df['State'] = df['RSI'].apply(determine_state)
# 2023년 이후 데이터만 필터링하여 시각화 준비
df2 = df[df.index.year >= 2023]
# 종가와 상태(State)를 시각화
plt.figure(figsize=(10, 5))
sns.lineplot(data=df2, x=df2.index, y='Close', hue='State')
plt.grid()
plt.show()
지수 이동 평균(Exponential Moving Average, EMA)을 사용하여 RSI를 계산
일반적으로, 표준 RSI는 단순 이동 평균(SMA)을 사용해 평균 상승폭과 평균 하락폭을 구하지만,
EWA(Exponential Weighted Average)를 사용하면 최신 데이터에 더 높은 가중치를 주어 RSI를 계산 가능함.
→ make_ewm_rsi 함수는 주어진 종가(close) 데이터에 대해 변화량(delta)을 구하고, 상승폭과 하락폭으로 나누어 지수 이동 평균을 이용해 RSI 값을 계산
import FinanceDataReader as fdr
import matplotlib.pyplot as plt
import seaborn as sns
# 1. 삼성전자 종가 데이터 불러오기
df = fdr.DataReader('005930') # 티커 '005930'은 삼성전자
# 2. 지수 이동 평균을 이용한 RSI 계산 함수 정의
def make_ewm_rsi(close, period=14):
delta = close.diff() # 종가 변화량 계산 (현재 종가 - 이전 종가)
gain = delta.where(delta >= 0, 0) # 상승폭: 양수만 남기고 나머지는 0으로 설정
loss = -delta.where(delta < 0, 0) # 하락폭: 음수는 양수로 변환하고 나머지는 0으로 설정
# 지수 가중 이동 평균을 이용해 14일 평균 상승폭과 평균 하락폭 계산
avg_gain = gain.ewm(span=period, adjust=False).mean()
avg_loss = loss.ewm(span=period, adjust=False).mean()
# RSI 계산
rsi = avg_gain / (avg_gain + avg_loss) * 100
return rsi
# 3. make_ewm_rsi 함수를 사용하여 RSI 열 생성
df['RSI'] = make_ewm_rsi(df['Close'])
# 4. RSI에 따라 매매 상태를 결정하는 함수 정의
def determine_state(x):
if x <= 30:
return 'Buy' # RSI가 30 이하일 때 매수 신호
elif x >= 70:
return 'Sell' # RSI가 70 이상일 때 매도 신호
else:
return 'Hold' # 그 외에는 보유 상태
# 5. RSI 값을 기반으로 상태(State) 열 생성
df['State'] = df['RSI'].apply(determine_state)
# 6. 2023년 이후 데이터만 필터링하여 시각화 준비
df2 = df[df.index.year >= 2023]
# 7. 종가와 매매 상태(State)를 시각화
plt.figure(figsize=(10, 5))
sns.lineplot(data=df2, x=df2.index, y='Close', hue='State') # 날짜별 종가와 매매 상태 표시
plt.grid()
plt.show()
finterstellar 라이브러리
# !pip install finterstellar
import finterstellar as fs
import matplotlib.pyplot as plt
df = fs.get_price('AAPL', start_date = '2024-01-01')
fs.draw_chart(df, right = 'AAPL') # 열이름
# 14일 이동 평균을 사용하여 RSI 지표 계산
fs.rsi(df, w=14)
fs.draw_chart(df, left = 'rsi', right = 'AAPL')
finterstellar 라이브러리를 사용하여 백테스팅을 수행하고, 애플(AAPL)의 주가 및 매매 포지션을 시각화
1. 매매 신호 생성
fs.indicator_to_signal(df, factor='rsi', buy=30, sell=70)
- fs.indicator_to_signal 함수는 RSI 지표를 기반으로 매매 신호를 생성
- factor='rsi'는 사용할 지표로 RSI를 지정
- buy=30은 RSI 값이 30 이하일 때 매수 신호를 발생시킴. (과매도 상태)
- sell=70은 RSI 값이 70 이상일 때 매도 신호를 발생시킴. (과매수 상태)
2. 포지션 상태 설명
매매 신호에 따라 주식의 포지션 상태는 다음과 같이 변화:
- zz: 현재 보유하지 않은 상태(Zero에서 Zero)이며, 새로운 매수나 매도 신호를 기다리는 중
- zl: 현재 보유하지 않은 상태에서 매수(Zero에서 Long)하여 보유 상태로 전환
- LL: 현재 Long(보유) 상태에서 계속 보유하는 상태
- Lz: 현재 보유 중인 주식을 매도하여 보유하지 않은 상태로 전환
fs.position(df)
4. 차트 시각화
fs.draw_chart(df, left='AAPL', right='position_chart')
- fs.draw_chart 함수는 주가 데이터프레임 df를 시각화
- left='AAPL'은 차트의 왼쪽 축에 애플(AAPL)의 주가 데이터를 표시하도록 설정
- right='position_chart'은 차트의 오른쪽 축에 포지션 상태(position)를 표시하도록 설정
→ RSI를 이용한 매매 신호를 생성하고, 이 신호를 기반으로 주식의 포지션 상태를 계산한 후, 애플(AAPL)의 주가와 포지션 상태를 시각적으로 표현
5. df에 대한 백테스트 결과를 평가
fs.evaluate(df, cost = 0.001) # 거래 수수료 (1% : 0.01)
- fs.evaluate: 주어진 데이터프레임 df의 백테스트 결과를 분석
- cost=0.001: 각 거래가 발생할 때마다 해당 거래의 금액의 0.1%가 수수료로 차감 → 거래 수수료를 설정함으로써 백테스트의 수익성을 보다 현실적으로 평가
6. 차트 시각화
fs.draw_chart(df, left='acc_rtn_dp', right='AAPL') # 누적 수익률과 AAPL 차트 시각화
→ 누적 수익률과 애플(AAPL) 주가 데이터를 시각화
7. 성과 평가
fs.performance(df, rf_rate=0.03) # 무위험 수익률을 3%로 설정하여 성과 지표 출력
performance: 투자 전략의 성과 지표를 계산하고 출력
- CAGR: 연평균 수익률을 나타내어 전략의 장기적인 성과를 평가
- Accumulated return: 누적 수익률을 통해 전체 투자 기간 동안의 총 수익률을 확인
- Average return: 모든 거래의 평균 수익률을 보여줌.
- 단순 보유 수익률: 매매 없이 주식을 단순 보유했을 때의 수익률을 계산하여 비교할 수 있다.
- 거래 횟수: 전체 거래의 수를 나타내어 전략의 활동성을 보여줌.
- 전략이 성공한 횟수: 수익이 발생한 거래의 수를 나타내어 전략의 성공률을 평가
- 성공확률: 성공적인 거래의 비율을 보여줌.
- 투자기간: 전략의 실행 기간을 측정
- 샤프 비율: 위험 대비 수익률을 나타내어 투자 전략의 효율성을 평가
- 최대 낙폭: 최대 손실 비율로 투자 중 가장 큰 손실을 나타.
- 담금: 누적 수익의 변화를 나타내는 지표
8. 거래 결과 시각화
fs.draw_trade_results(df) # 거래 결과 시각화
draw_trade_results: 백테스트의 거래 결과를 시각적으로 표현. 각 거래의 수익 및 손실을 그래픽으로 시각화는 거래 성과의 패턴을 분석하고, 성공적인 거래와 실패한 거래를 구분할 수 있음.
볼린저 밴드를 활용한 투자 전략
1. 데이터 가져오기
df = fs.get_price('TSLA', start_date='2024-01-01') # TSLA의 주가 데이터를 2024년 1월 1일부터 가져오기
fs.get_price: Tesla(TSLA)의 주가 데이터를 가져옵니다. 데이터프레임 df에는 주가, 거래량 등의 정보가 포함
2. 볼린저 밴드 계산
fs.bollinger(df, w=20, k=2) # 20일 기준, 2 표준편차로 볼린저 밴드 계산
fs.bollinger: 주어진 데이터프레임 df에 대해 볼린저 밴드를 계산
- w=20: 이동 평균의 기간을 20일로 설정
- k=2: 표준편차의 배수를 2로 설정하여 상한선과 하한선을 결정 → 이는 주가의 변동성을 반영
3. 밴드 차트 시각화
fs.draw_band_chart(df) # 볼린저 밴드를 포함한 차트 시각화
fs.draw_band_chart: 볼린저 밴드를 포함한 주가 차트를 시각화하여, 주가가 볼린저 밴드의 상한선과 하한선 사이에서 어떻게 움직이는지 보여줌
4. 매매 신호 생성
fs.band_to_signal(df, buy='D', sell='A') # 매수 및 매도 신호 생성
fs.band_to_signal: 볼린저 밴드를 기반으로 매매 신호를 생성
- buy='D': 주가가 하한선을 아래로 돌파할 때 매수 신호를 발생시킴
- sell='A': 주가가 상한선을 위로 돌파할 때 매도 신호를 발생시킴
5. 포지션 계산
fs.position(df) # 포지션 계산 및 상태 업데이트
fs.position: 매매 신호에 따라 현재 포지션(매수, 매도 또는 보유 상태)을 계산. 이를 통해 각 시점에서 투자자의 현재 보유 상태를 업데이트
6. 전략 평가
fs.evaluate(df, cost=0.001) # 거래 수수료를 0.1%로 설정하여 전략 평가
fs.evaluate: 백테스트의 성과를 평가. 거래 수수료를 반영하여 전략의 수익성과 성과 지표를 계산
7. 성과 지표 출력
fs.performance(df, rf_rate=0.03) # 무위험 수익률을 3%로 설정하여 성과 지표 출력
fs.performance: 전략의 성과 지표를 계산하고 출력7. 여기에는 CAGR, 누적 수익률, 거래 횟수 등이 포함됨
8. 거래 결과 시각화
fs.draw_trade_results(df) # 거래 결과 시각화
fs.draw_trade_results: 백테스트의 거래 결과를 시각적으로 표현. 각 거래의 수익 및 손실을 그래픽으로 나타냄.
RSI(상대 강도 지수)와 볼린저 밴드를 결합하여 투자 전략을 세우고 평가
#!pip install finterstellar # finterstellar 패키지가 설치되어 있지 않은 경우 주석 해제하여 설치
import finterstellar as fs # finterstellar 패키지 가져오기
import matplotlib.pyplot as plt # matplotlib 가져오기
# 1. 데이터 가져오기
df = fs.get_price('TSLA', start_date='2024-01-01') # TSLA의 주가 데이터를 2024년 1월 1일부터 가져오기
# df 데이터프레임에는 주가, 거래량 등의 정보가 포함됨
# 2. RSI 계산
fs.rsi(df, w=14) # 14일 기간으로 RSI를 계산하여 df에 추가
# RSI는 주가의 과매수 또는 과매도 상태를 나타내는 지표
# 3. 볼린저 밴드 계산
fs.bollinger(df, w=20, k=2) # 20일 기준, 2 표준편차로 볼린저 밴드를 계산하여 df에 추가
# 볼린저 밴드는 주가의 변동성을 나타내는 기술적 지표
# 4. 매매 신호 생성 (RSI)
df['s1'] = fs.indicator_to_signal(df, factor='rsi', buy=30, sell=70) # RSI를 기반으로 매매 신호 생성
# 's1' 열에 RSI 기준으로 매수 신호(30 이하)와 매도 신호(70 이상)를 기록
# 5. 매매 신호 생성 (볼린저 밴드)
df['s2'] = fs.band_to_signal(df, buy='D', sell='A') # 볼린저 밴드를 기반으로 매매 신호 생성
# 's2' 열에 볼린저 밴드 기준으로 매수 신호(하한선 아래)와 매도 신호(상한선 위)를 기록
# 6. 신호 결합
fs.combine_signal_and(df, 's1', 's2') # RSI와 볼린저 밴드 신호 결합
# 두 신호가 동시에 매수 또는 매도 신호를 줄 때만 거래를 실행하도록 설정
# 7. 포지션 계산
fs.position(df) # 매매 신호에 따라 현재 포지션 계산 및 상태 업데이트
# 투자자의 현재 보유 상태를 업데이트하여 매수, 매도 또는 보유 상태로 표시
# 8. 전략 평가
fs.evaluate(df, cost=0.001) # 거래 수수료를 0.1%로 설정하여 전략 평가
# 거래 수수료를 반영하여 전략의 수익성과 성과 지표를 계산
# 9. 성과 지표 출력
fs.performance(df, rf_rate=0.03) # 무위험 수익률을 3%로 설정하여 성과 지표 출력
# CAGR, 누적 수익률, 거래 횟수 등의 성과 지표를 출력하여 전략의 효율성 평가
# 10. 거래 결과 시각화
fs.draw_trade_results(df) # 거래 결과를 시각적으로 표현
# 각 거래의 수익 및 손실을 그래픽으로 나타내어 전략의 성과를 직관적으로 이해할 수 있도록 함
전체 과정 설명
- 데이터 가져오기: TSLA의 주가 데이터를 지정한 날짜부터 가져옴.
- RSI 계산: 상대 강도 지수(RSI)를 14일 기준으로 계산. RSI는 주가의 과매수 또는 과매도 상태를 나타내는 지표
- 볼린저 밴드 계산: 20일 이동 평균을 기준으로 표준편차의 2배를 상한선과 하한선으로 설정하여 볼린저 밴드를 계산. 이는 주가의 변동성을 보여주는 지표
- 매매 신호 생성 (RSI): RSI를 기반으로 매수 및 매도 신호를 생성하여 데이터프레임에 추가함. 30 이하일 경우 매수, 70 이상일 경우 매도 신호를 발생시킴.
- 매매 신호 생성 (볼린저 밴드): 볼린저 밴드의 상한선과 하한선을 기준으로 매수 및 매도 신호를 생성
- 신호 결합: 두 신호가 동시에 발생할 때만 거래를 실행하도록 결합. 이를 통해 더 신뢰성 있는 매매 신호를 얻음.
- 포지션 계산: 생성된 매매 신호를 바탕으로 현재 포지션을 계산. 매수, 매도 또는 보유 상태로 투자자의 포지션을 업데이트.
- 전략 평가: 거래 수수료를 반영하여 전략의 성과를 평가. 수익성과 관련된 지표를 계산.
- 성과 지표 출력: CAGR(연평균 성장률), 누적 수익률, 거래 횟수 등의 성과 지표를 출력하여 전략의 효율성을 평가
- 거래 결과 시각화: 거래 결과를 시각적으로 표현하여 전략의 성과를 직관적으로 이해할 수 있도록 함.
특정 디렉토리 내의 이미지를 모아 애니메이션 GIF를 생성
import os # 운영 체제 기능을 사용하기 위한 모듈
import matplotlib.pyplot as plt # 데이터 시각화를 위한 모듈
import matplotlib.animation as animation # 애니메이션을 만들기 위한 모듈
from PIL import Image # 이미지 처리를 위한 Python Imaging Library (PIL)
# 이미지 저장을 위한 빈 리스트 초기화
images = []
# '배당' 폴더 내의 모든 파일을 순회
for i in os.listdir("배당"):
# 각 이미지 파일을 열고 리스트에 추가
a = Image.open("배당/" + i) # 이미지 파일 경로 설정
images.append(a) # 리스트에 이미지 추가
# 애니메이션을 생성할 그림과 축 설정
fig, ax = plt.subplots(figsize=(6, 8)) # 그림 크기 설정
ax.axis("off") # 축 숨기기 (이미지만 표시)
# 각 프레임을 업데이트하는 함수 정의
def update_frame(x):
ax.imshow(images[x]) # 이미지 리스트에서 현재 프레임에 해당하는 이미지 표시
# 애니메이션 생성
ani = animation.FuncAnimation(fig, update_frame, frames=len(images), interval=1000, repeat=True)
# FuncAnimation을 사용하여 애니메이션을 설정
# - fig: 애니메이션이 그려질 Figure 객체
# - update_frame: 각 프레임을 업데이트하는 함수
# - frames: 총 프레임 수 (이미지 수)
# - interval: 프레임 간의 시간 간격 (1000 ms = 1초)
# - repeat: True로 설정하면 애니메이션이 반복됨
# 애니메이션을 GIF 파일로 저장
ani.save("animation.gif", writer="imagemagick") # 'animation.gif' 파일명으로 저장