파이썬 & 머신러닝과 딥러닝

RSI, 볼린저 밴드를 활용한 투자 전략 (EMA, finterstellar 라이브러리 사용)

hyuniiie 2024. 10. 29. 13:29

RSI (Relative Strength Index, 상대 강도 지수)

주식, 외환, 암호화폐 등 금융 상품의 가격이 과매도 또는 과매수 상태에 있는지를 판단하는 지표로 사용

 

 

  • RSI ≥ 70: 과매수 상태를 나타내며, 가격이 고평가될 가능성 ↑. 이때 매도 신호로 해석
  • RSI ≤ 30: 과매도 상태를 나타내며, 가격이 저평가될 가능성 ↑ . 이때 매수 신호로 해석

 

 

RSI 계산 과정

  1. 변화량 계산: 특정 주기의 종가 변화를 구해 상승폭과 하락폭을 구한다.
  2. AU (Average Up): 일정 기간 동안의 평균 상승폭.
  3. DU (Average Down): 일정 기간 동안의 평균 하락폭.
  4. 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)  # 거래 결과를 시각적으로 표현
# 각 거래의 수익 및 손실을 그래픽으로 나타내어 전략의 성과를 직관적으로 이해할 수 있도록 함

 

전체 과정 설명

  1. 데이터 가져오기: TSLA의 주가 데이터를 지정한 날짜부터 가져옴.
  2. RSI 계산: 상대 강도 지수(RSI)를 14일 기준으로 계산. RSI는 주가의 과매수 또는 과매도 상태를 나타내는 지표
  3. 볼린저 밴드 계산: 20일 이동 평균을 기준으로 표준편차의 2배를 상한선과 하한선으로 설정하여 볼린저 밴드를 계산. 이는 주가의 변동성을 보여주는 지표
  4. 매매 신호 생성 (RSI): RSI를 기반으로 매수 및 매도 신호를 생성하여 데이터프레임에 추가함. 30 이하일 경우 매수, 70 이상일 경우 매도 신호를 발생시킴.
  5. 매매 신호 생성 (볼린저 밴드): 볼린저 밴드의 상한선과 하한선을 기준으로 매수 및 매도 신호를 생성
  6. 신호 결합: 두 신호가 동시에 발생할 때만 거래를 실행하도록 결합. 이를 통해 더 신뢰성 있는 매매 신호를 얻음.
  7. 포지션 계산: 생성된 매매 신호를 바탕으로 현재 포지션을 계산. 매수, 매도 또는 보유 상태로 투자자의 포지션을 업데이트.
  8. 전략 평가: 거래 수수료를 반영하여 전략의 성과를 평가. 수익성과 관련된 지표를 계산.
  9. 성과 지표 출력: CAGR(연평균 성장률), 누적 수익률, 거래 횟수 등의 성과 지표를 출력하여 전략의 효율성을 평가
  10. 거래 결과 시각화: 거래 결과를 시각적으로 표현하여 전략의 성과를 직관적으로 이해할 수 있도록 함.

 

 

 


특정 디렉토리 내의 이미지를 모아 애니메이션 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' 파일명으로 저장