본문 바로가기
Python

파이썬을 이용한 RSI Divergence 구현

by 아짱이아빠 2022. 11. 19. 23:52
반응형

이번에는 파이썬을 이용하여 RSI Divergence 구간을 찾아 매수를 하고 RSI가 과매도 구간에서 매도를 하는 것에 대해 알아보겠다.

 

[ RSI Divergence ]

RSI Divergence에 대해 간단히 알아보면 다음과 같다.

먼저 RSI(Relative Strength Index)는 주가나 또는 가상화폐 시세의 흐름을 파악할 때 사용하는 유명한 지표 중 하나이다.

일반적으로 RSI가 30 밑으로 가면 과매도가 발생했고 곧 가격이 반등할 것이라고 예측하며 70 이상이 되면 과매수가 발생하여 가격이 곧 하락할 것으로 예측한다.  

 

RSI Divergence는 가격의 흐름이 바뀌기 이전에 RSI의 흐름을 통해 가격 모멘텀이 바뀔것임을 예측하는 데 사용된다. 

RSI Divergence에는 앞으로 가격의 하락을 예측해보는 Bearish Divergence와 가격의 상승을 예측하는 Bullish Divergence가 있는데 여기서는 Bullish Divergence에 대해서만 얘기하겠다.

Bullish Divergence는 RSI의 과매도(oversold) 구간에서 이전의 최소치 보다는 증가하는 형태를 갖고 동시에 실제 가격은 같은 구간에서 하락을 하는 형태를 갖는 것을 말한다.

아래의 그래프에서 RSI는 최저점이 상승하는 형태이며 이때 보통은 가격이 상승하지만 여기에서는 반대로 가격이 하락을 한다.

이러한 구간을 RSI Divergence라 부르며 이 후 가격의 모멘텀이 바뀌어 하락하던 가격이 상승할 것으로 기대를 하게 된다. 

RSI Divergence 설명
(RSI Divergence 설명)

 

[ RSI Divergence 파이썬 코드 ]

파이썬 코드는 가상화폐 OHLC 데이터를 불러와서 먼저 RSI를 계산하고 이를 이용하여 RSI Divergence 구간을 찾는 로직을 통해 구간을 확인한다.

RSI Divergence 구간이 확인되면 이후 RSI가 과매도 구간을 벗어나는 시점에 매수를 하고 RSI가 과매수 구간에서 매도를 하는 로직이다.

!pip install pyupbit
import pyupbit
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

coin = input("코인 :")
df = pyupbit.get_ohlcv(coin,interval="minutes5", count=200)

위 코드는 프로그램에 필요한 모듈을 설치하고 다운받고자 하는 가상화폐를 입력하면 업비트에서 데이터를 다운로드한다.

위 코드는 5분봉 데이터 200개를 다운로드하도록 되어있으며 이는 변경이 가능하다.

 

다음은 RSI를 계산하는 코드인데 이에 대한 설명은 다른 포스트에도 많이 나와 있으므로 넘어가도록 하겠다.

delta = df['close'].diff(1)
delta = delta.dropna()
up = delta.copy()
down = delta.copy()
up[ up < 0 ] = 0
down[ down > 0 ] = 0
time_period_9 = 9
AVG_Gain_9 = up.ewm(com=time_period_9-1, min_periods=time_period_9).mean()
AVG_Loss_9 = abs(down.ewm(com=time_period_9-1, min_periods=time_period_9).mean())
RS_9 = AVG_Gain_9 / AVG_Loss_9
RSI_9 = 100.0 - (100.0/(1.0 + RS_9))
df['RSI_9'] = RSI_9

 

다음은 이 프로그램의 핵심이 되는 부분으로 RSI Divergence 구간을 찾고 매수와 매도의 조건을 확인한다.

high_barrier = 70
low_barrier = 30
Buy_Price=[]
Sell_Price=[]
number = []
temp01 = []
temp01_id = []
temp02 = []
temp02_id = [] 
temp01_min_price = []
temp02_min_price = []
temp01_min_rsi = []
temp02_min_rsi = []
n_id =[]
i_id=[]
flag=1
n=0

for i in range (len(df)):
  if df['RSI_9'][i-1] > low_barrier and df['RSI_9'][i] < low_barrier:
    for k in range(i,len(df)):
      if df['RSI_9'][k-1] < low_barrier and df['RSI_9'][k] > low_barrier:
        temp01 = df['RSI_9'].iloc[i:k]
        temp01_id = temp01.argmin()+i
        temp01_min_rsi = df['RSI_9'][temp01_id]
        temp01_min_price = df['close'][temp01_id]

        for m in range(k, len(df)):
          if df['RSI_9'][m-1] > low_barrier and df['RSI_9'][m] < low_barrier:

            for n in range(m, len(df)):
              if df['RSI_9'][n-1] < low_barrier and df['RSI_9'][n] > low_barrier:
                temp02 = df['RSI_9'].iloc[m:n]
                temp02_id = temp02.argmin()+m
                temp02_min_rsi = df['RSI_9'][temp02_id]
                temp02_min_price = df['close'][temp02_id]

                if temp01_min_rsi < temp02_min_rsi and temp01_min_price > temp02_min_price and flag==1 :
                  Buy_Price.append(df['close'][n])
                  n_id.append(n)
                  flag=0
                break

          if flag == 0 and n != 0:
            for p in range (n, len(df)):
              if df['RSI_9'][p-1] > high_barrier and df['RSI_9'][p-1] > df['RSI_9'][p] and flag == 0:
                Sell_Price.append(df['close'][p])
                i_id.append(p)
                flag=1

  

위 로직을 간단히 설명하면 다음과 같다.

먼저 RSI 과매수 구간과 과매도 구간은 각각 "high_barrier" 70과 "low_barrier" 30으로 설정하고 그 외에 로직에 필요한 변수들을 설정한다.

 

전체 로직은 for 문을 통해 순차적으로 수행된다. 

처음 RSI가 "low_barrier" 기준 이하로 내려가면, 그 시점부터 다시 RSI가 "low_barrier" 기준 위로 올라갈 때까지를 확인하여 그 구간에서의 RSI 최솟값과 그때의 가격을 변수에 저장한다.

 

이 시점부터 다시 RSI가 그다음 "low_barrier" 기준 아래로 내려가는 시점과 또다시 "low_barrier" 기준 위로 올라갈 때까지를 확인하여 역시 이 구간에서의 RSI 최솟값과 가격을 변수에 저장한다.

 

이제 첫 번째로 RSI가 "low_barrier" 기준 밑으로 갔다가 올라왔을 때에 저장한 RSI 및 가격과 두 번째로 RSI가 "low_barrier" 기준 밑에 있다가 올라올 때의 값과 각각 비교하여 RSI Divergence가 발생했는지 확인한다.

즉, RSI 최솟값은 증가하고 이때의 가격은 하락했다면 RSI Divergence가 발생하였으며

매수는 이 조건이 성립하고 RSI가 "low_barrier" 기준을 넘을 때이며 변수 ”Buy_Price”에 저장한다.

 

매도는 RSI가 "high_barrier" 기준을 넘었고 이전 RSI보다 현재의 RSI가 낮아졌다면 그때 매도를 하는 로직이다.

이 순간에 가격을 변수 “Sell_Price”에 저장한다.

 

반응형

 

[ Backtesting 결과 ]

다음은 이 로직으로 다음의 몇 가지 가상화폐에 대해 backtesting 한 결과이다.

 

(샌드박스(SAND) - 5분봉 데이터)

아래는 가상화폐 샌드박스(SAND)의 11월 12일 04시부터 20시까지의 5분봉 데이터 중 종가와 RSI를 그래프로 나타낸 것이다.

샌드박스(SAND)의 RSI Divergence 예측 구간
(샌드박스(SAND)의 RSI Divergence 예측 구간)

위의 그림에서 화살표가 나타내는 구간을 보면, 가격은 하락하지만 RSI는 증가했으며 RSI Divergence가 발생했다.

이 구간에서 매수가 일어날 것이고 이후 약 16시가 조금 넘은 지점에서 매도가 이뤄질 것이다.

그래프에서 다른 구간의 예를 들면, 10시 조금 넘은 시점과 12시가 넘은 시점을 비교할 때 RSI가 증가했지만 이 지점들에서의 가격은 하락하지 않고 올라갔기 때문에 RSI Divergence가 발생했다고 볼 수 없을 것이다.

 

다음은 로직에 의해 매수와 매도가 이루어진 가격을 나타낸다.

샌드박스(SAND)의 RSI Divergence 예측에 의한 매수와 매도 결과
(샌드박스(SAND)의 RSI Divergence 예측에 의한 매수와 매도 결과)

 

위의 그래프에서 녹색 삼각형은 매수를, 빨간색 삼각형은 매도를 나타낸다.

매수 가격은 819원이고 매도 가격은 843원으로 약 3%의 수익이 가능하다.

 

 

(비트코인(BTC) - 5분봉 데이터)

다음은 비트코인(BTC)의 같은 시간데의 5분봉 데이터이다.

비트코인(BTC)의 RSI Divergence 예측 구간
(비트코인(BTC)의 RSI Divergence 예측 구간)

앞에서의 샌드박스와 유사하게 14시 부근에 RSI Divergence가 이뤄졌을 것으로 보인다.

 

비트코인(BTC)의 RSI Divergence 예측에 의한 매수와 매도 결과
(비트코인(BTC)의 RSI Divergence 예측에 의한 매수와 매도 결과)

Bactesting 결과 역시 예측 시점에서 매수와 매도가 이뤄지고 매수 가격은 23,123,000원이고 매도 가격은 23,433,000원으로 수익률은 약 1.3%이다.

 

 

(칠리즈(CHZ)-5분봉 데이터)

마지막은 칠리즈(CHZ)의 역시 비슷한 시간대의 데이터이다.

칠리즈(CHZ)의 RSI Divergence 예측 구간
(칠리즈(CHZ)의 RSI Divergence 예측 구간)

여기서는 데이터의 앞부분인 12일 4시에서 6시 사이에 RSI Divergence가 발생했다. 

이후에는 12일 14시 부근에서 RSI가 증가하고 가격은 하락했으나 RSI가 "low_barrier" 기준인 30을 넘지 않았기 때문에 로직에서는 RSI Divergence로 판단하지 않을 것이다.

 

칠리즈(CHZ)의 RSI Divergence 예측에 의한 매수와 매도 결과
(칠리즈(CHZ)의 RSI Divergence 예측에 의한 매수와 매도 결과)

 

앞에서 예측한 바와 같이 매수와 매도 결과는 앞부분에서만 이뤄지고 이후에는 발생하지 않았다.

매수 가격은 295원이고 매도 가격은 310원으로 수익률은 약 5%이다.



[ 결 론 ]

RSI Divergence를 파이썬 코드를 통해 확인하는 로직과 몇 가지의 가상화폐 데이터를 가지고 이를 기준으로 한 매수와 매도 시 수익률도 알아봤다.

 

몇 가지의 가상화폐를 통한 backtesting에서는 수익률은 작지만 손해를 보지는 않았다.

그렇지만 이는 어느 정도 데이터 샘플 선정에 운이 있었던 것으로 생각된다.

또한 매매 전략은 RSI 매수와 매도의 조건을 변경한다던지 5분봉 기준이 아닌 15분 또는 30분 기준으로 했을 때의 결과는 또 다를 것이다.

 

이 코드를 실시간 매매로 활용하기 위해서는 수정이 좀 필요할 것이다.

여기서의 코드는 데이터를 앞에서부터(과거부터) 뒤쪽으로(현재로) 읽어가면서 로직을 수행하지만, 실시간 매매에서 코드를 활용하기 위해서는 현재의 시점에서 과거의 시점으로 읽어가면서 RSI Divergence 조건을 찾도록 해야 할 것이다.

이를 위해서는 코드의 많은 변경이 필요할 것이다.

또는 RSI Divergence 시점이 현재의 시점인지를 비교하는 코드를 추가하는 방법도 가능할 것 같다.

 

다음에는 RSI Divergence를 실시간 매매에 활용하는 코드에 대해 준비할 계획이다.

 

반응형

댓글