
RSI의 수식, 엑셀과 트레이딩뷰로 구현해보기
*2021-10-05 글
RSI란 Relative Strength Index의 약자로, 상대강도지수를 의미합니다.
0에서 100사이의 수치로 나타나며, 과매수 혹은 과매도 여부를 판단할 때 사용되는 것으로 알려져 있습니다.
어떻게 과매수와 과매도 여부를 판단한다는 것일까요?
정말 단순하게도, 본 지표에서는 평균 상승폭 대비 평균 하락폭으로 이를 판단합니다.
그러나 단순히 평균 상승폭이 더 크다고해서 과열이라고 말할 수는 없습니다. 이 때문에 RSI에서는 수치가 특정 구간을 이탈했을 때를 과열이라고 칭하는 것입니다.
ex) RSI가 70이상일 때 과매수, RSI가 30이하일 때 과매도
그러나 RSI는, 변동성이 커 특정 구간 이탈이 쉬운 종목의 과열 여부를 설명하지 못한다는 한계가 존재합니다.
RSI가 70이상을 유지하며 지속적으로 상승을 보이는 모습
RSI의 수식은 다음과 같습니다.
RS = N일 간 평균 상승 폭 / N일 간 평균 하락 폭
RSI = 100 - 100/(1+RS)
두번째 수식은 RSI를 0 ~ 100 사이의 수치로 나오게 만들기 위한 식입니다.
Wilder's RSI와 Cutler's RSI
간혹 증권사마다 RSI의 수치가 달리 표기되는 경우가 있습니다.
이는 계산 방법의 차이에 의한 것인데,
Wilder's RSI는 RS를 구할 때 지수이동평균
RS = N일 간 상승 폭의 지수평균 / N일 간 하락 폭의 지수평균
Cutler's RSI는 RS를 구할 때 단순이동평균을 사용한 정도의 차이입니다.
RS = N일 간 상승 폭의 단순평균 / N일 간 하락 폭의 단순평균
Backtest
카카오를 대상으로, 2000년 2월부터 2021년 9월까지 RSI를 사용한 "Long Only" 백테스팅 결과입니다.
모든 백테스트는 리스크 관리를 따로 하지 않았으며, 조건에 따라 자산의 100%를 전부 운용했을 때의 결과입니다.
RSI 설정 값은 14, Cutler's RSI 기준입니다.
1.
매수 조건: RSI가 30 이하일 때
매도 조건: RSI가 70 이상일 때
Sharpe Ratio = 0.098
Sortino Ratio = 0.145
승률과 손익이 둘 다 준수하지만, MDD는 63.5%가 나왔습니다.
진입 이후, RSI가 70이 채 되지 못해 실현하지 못한 경우에 의한 결과입니다.
2.
매수 조건: RSI가 30 이하일 때
매도 조건: RSI가 30 이상일 때
Sharpe Ratio = 0.024
Sortino Ratio = 0.032
그래서 실현 기준을 더 낮췄습니다.
RSI 상에서 과매도가 나왔을 때 진입하여, 과매도 구간을 벗어났을 때 실현을 한 전략입니다.
더 낮아진 실현 기준에 의해 불필요한 거래가 빈번히 일어났으며, 불필요한 거래들이 손익비와 승률에 영향을 미친 듯 합니다.
3.
매수 조건: 종가(close)가 20일 평균선을 돌파하였을 때
매도 조건: RSI가 70 이상일 때
Sharpe Ratio = 0.137
Sortino Ratio = 0.223
실현 기준을 그대로 두고, 진입 기준을 RSI가 아닌 추세를 기준으로 잡았습니다.
과열 여부만을 판단하기 위함입니다.
그 결과, 손익, 승률, MDD까지 개선 된 모습을 보입니다.
본 백테스팅 상에서는 RSI으로 진입 기준을 세우는 것 보다, 실현이 고민 될 때 참고하는 것이 더 효율적인 모습을 보이고 있습니다.
Excel
1. RS
RS를 구하기 위해서는, 먼저 상승 및 하락 분을 알아야 할 필요가 있습니다.
오늘의 종가값 - 어제의 종가값
"=B3-B2"
상승하락분이 양수라면 상승분, 아니라면 0을 나타내는 조건식을 추가해줍니다.
"=IF(D3>0,D3,0)"
다음 셀에는 반대로, 상승하락분이 음수라면 하락분(절대값), 아니라면 0을 나타내는 조건식을 추가해줍니다.
"=IF(D3<0,ABS(D3),0)"
A의 평균과 B의 평균을 입력해주세요.
저는 14일 평균으로 나타냈습니다.
"=AVERAGE(E3:E16)"
그 다음 A/B를 해주시면 RS가 완성됩니다.
"=G16/H16"
2. RSI
RSI = 100 - 100/(1+RS) 였습니다.
RS 그대로 적용시켜주시면 됩니다.
"=100 - 100/(1+I16)"
TradingView
TradingView에서는 친절한 함수를 제공합니다.
rsi(close, 기간)
기간에 임의의 값을 입력한 이후, plot하시면 RSI가 완성됩니다. 기간을 매번 바꾸는 것이 번거로우실 때는, 아래와 같이 integer를 추가해주시면 됩니다.
//@version=4 study("rsi") N=input(defval=14,type=input.integer) rsi=plot(rsi(close,N),color=color.black,linewidth=2)
만일 위 사진자료처럼 선만 그어진 RSI가 아닌 더 깔끔한 모양을 원하시는 분은, 테두리를 정의한 후 fill 함수를 사용해주시면 됩니다.
//@version=4 study("rsi") N=input(defval=14,type=input.integer) rsi=plot(rsi(close,N),color=color.black,linewidth=2) r7=plot(70,color=color.red,style=plot.style_circles) r3=plot(30,color=color.blue,style=plot.style_circles) fill(rsi,r7,color=rsi(close,14)>=70?color.red:na,transp=50) fill(rsi,r3,color=rsi(close,14)<=30?color.blue:na,transp=50)
TradingView에서 제공하는 rsi함수가 아닌, 위에서 학습한대로 제작하는 방법은 다음과 같습니다.
먼저 Cutler's RSI입니다.
A = 양봉일때 상승분만큼의 평균
B = 음봉일 때 하락분만큼의 평균 (절대값)
RS = A/B
rsi = RS를 0에서 100사이의 값으로 나타나게 만드는 수식
//@version=4 study("Cutler's RSI") N=input(defval=14,type=input.integer) A=sma(iff(0<close-close[1], close-close[1], 0), N) B=sma(iff(0>close-close[1], abs(close-close[1]), 0), N) RS=A/B rsi=100 - 100/(1+RS) rsii=plot(rsi,color=color.black,linewidth=2) r7=plot(70,color=color.red,style=plot.style_circles) r3=plot(30,color=color.blue,style=plot.style_circles) fill(rsii,r7,color=rsi>=70?color.red:na,transp=50) fill(rsii,r3,color=rsi<=30?color.blue:na,transp=50)
다음으로 Wilder's RSI 입니다.
A와 B를 정의하는 과정에서, sma 대신 ema를 사용해주시면 지수이동평균으로 사용하실 수 있습니다.
//@version=4 study("Wilder's RSI") N=input(defval=14,type=input.integer) A=ema(iff(0<close-close[1], close-close[1], 0), N) B=ema(iff(0>close-close[1], abs(close-close[1]), 0), N) RS = A/B rsi=100 - 100/(1+RS) rsii=plot(rsi,color=color.black,linewidth=2) r7=plot(70,color=color.red,style=plot.style_circles) r3=plot(30,color=color.blue,style=plot.style_circles) fill(rsii,r7,color=rsi>=70?color.red:na,transp=50) fill(rsii,r3,color=rsi<=30?color.blue:na,transp=50)