RSI 전략을 만들기 위한 참고
2022.11.01 - [개발일지] - 1. 투자지표를 활용한 매매 시점 모니터링 - 개요
2022.11.07 - [개발일지] - 2. 투자지표를 활용한 매매 시점 모니터링 - RSI, RMI
2022.11.07 - [개발일지] - 3. 투자지표를 활용한 매매 시점 모니터링 - 벡테스팅
2022.11.08 - [개발일지] - 4. 투자지표를 활용한 매매 시점 모니터링 - 시각화
2022.11.08 - [개발일지] - 5. 투자지표를 활용한 매매 시점 모니터링 - Kospi 종목 벡테스팅
2022.11.09 - [개발일지] - 6. 투자지표를 활용한 매매 시점 모니터링 - 손절선
2022.11.10 - [개발일지] - 7. 투자지표를 활용한 매매 시점 모니터링 - 다중 종목 벡테스팅
총 7편에 나누어 RSI 소개와 시각화, 벡테스팅 등 주요 기능을 구현하였다.
이제 가장 중요한 전략을 세워야 하는데 그전에 RSI의 30, 70 선에 대한 매매 기준 도달 횟수를 확인해 보았다.
이유는 매수, 매도 시그널이 과도하게 많이 발생하지 않는지, 한쪽으로 쏠려있지 않은지 등을 확인하기 위함이다.
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import FinanceDataReader as fdr
import copy
def rsi(ohlc: pd.DataFrame,y_label, period: int = 14):
delta = ohlc[y_label].diff()
ups, downs = delta.copy(), delta.copy()
ups[ups < 0] = 0
downs[downs > 0] = 0
AU = ups.ewm(com = period-1, min_periods = period).mean()
AD = downs.abs().ewm(com = period-1, min_periods = period).mean()
RS = AU/AD
return pd.Series(100 - (100/(1 + RS)), name = "RSI")
df_krx = fdr.StockListing('KRX')
kospi_data = df_krx[(df_krx["Market"]=="KOSPI") & (~df_krx["Sector"].isna())]
stock_list = list(kospi_data.Name)
우선 위의 코드를 실행시켜 필요한 패키지와 Kospi 종목만 추린다.
%%time
lower_cut = 30
upper_cut = 70
check_df = None
for i, kn in enumerate(stock_list):
print(i,kn)
ks = df_krx[df_krx["Name"]==kn].Symbol.values[0]
price_data1 = fdr.DataReader(ks,"2020")
price_data1["stock_name"]= kn
RSI_df = np.round(rsi(price_data1, "Close",14),2)
price_data1["RSI"] = RSI_df
price_data1["RSI_signal"] = np.round(price_data1["RSI"].rolling(9).mean(),2)
price_data1["lower"] = None
price_data1["upper"] = None
price_data1["buy_tag"] = 0
price_data1["sell_tag"] = 0
lower_list = False
upper_list = False
now_index_list = 0
for ti in price_data1.index:
tmp = price_data1[price_data1.index == ti]
now_index_list = tmp.RSI.values[0]
if now_index_list <=lower_cut:
lower_list = True
elif now_index_list > lower_cut and lower_list == True:
lower_list = False
price_data1.loc[price_data1.index == ti,"buy_tag"] = 1
print("buy")
elif now_index_list >upper_cut:
upper_list = True
elif now_index_list <= upper_cut and upper_list == True:
upper_list = False
price_data1.loc[price_data1.index == ti,"sell_tag"] = 1
print("sell")
price_data1.loc[price_data1.index == ti,"lower"] = lower_list
price_data1.loc[price_data1.index == ti,"upper"] = upper_list
check_df = pd.concat([check_df,price_data1],axis = 0)
2022년을 대상으로 매매 횟수를 확인하려 하는데, RSI 계산 시 과거 150일가량의 데이터가 있어야 네이버 RSI 계산 값과 동일하여 2020년부터 데이터를 가져온 후 RSI 값 산출, 매매 시그널 산출을 진행한다.
RSI signal은 RSI의 9일 이동평균을 산출했다. 참고가 될 수 있을 것 같아 RSI와 같이 보기로 한다.
전략은 동일하게 30선과 70선을 이용한 매매이다.
30선 이하로 내려가면 매수 트리거가 켜지고 30 이상으로 올라갈 때 매수한다.
70선 이상으로 올라가면 매도 트러거가 켜지고 70 이하로 내려갈 때 매도한다.
check_df = check_df[check_df.index>"2022"]
2022년 데이터만 확인하기 위해 날짜 형식으로 되어있는 index를 이용한다.
c1 = check_df[check_df["stock_name"]=="KT&G"].copy()
c1[(c1["buy_tag"]==1) | (c1["sell_tag"]==1)]
c1["lower_cut"] = 30
c1["upper_cut"] = 70
fig, ax1 = plt.subplots(figsize = (14,7))
ax1.set_ylabel('Price')
ax1.plot(c1["Close"],color = "tab:red",alpha = 1)
ax2 = ax1.twinx()
ax2.set_ylabel('Index')
ax2.plot(c1["RSI"],color = "green",alpha = 0.3)
ax2.plot(c1["lower_cut"],color = "blue",alpha = 0.2)
ax2.plot(c1["upper_cut"],color = "red",alpha = 0.2)
plt.title(c1["stock_name"].values[0])
plt.legend(["RSI"],loc = 'upper right')
plt.show()
전략의 단점을 보여주는 하나의 예시로 KT&G를 조회해보았다.
매매 시그널이 얼마나 발생했는지, 30, 70선을 그린 후 시각화로 보자.
2022년 약 10개월 동안 총 4번의 매수 시그널과 7번의 매도 시그널이 나타났다.
1월에 매수 시그널이 몰려있고 5월 이후 매도 시그널이 나타났다. 이렇게 보면 보기 어려우니 시각화를 해보자.
빨간색 선이 왼쪽 축으로 가격을 나타낸다. 연두색선이 오른쪽 축으로 RSI이다.
이상한 것이 보이지 않는가? 1월에 매수 시그널이 발생했을 때를 보면 30선 근처에서 진동하고 있어 계속해서 발생했던 것이다. 만약 자동매매를 했다면 총 4번의 비슷한 가격에서 총 4번의 매수를 했을 것이다.
매도의 경우도 5월 경에 70선에서 두 번, 9월경에 3번이 발생했는데, 이도 마찬가지로 70선에서 진동하며 계속 시그널이 발생했던 것이다.
물론 79,200 / 78,900 / 79,000 / 77,600으로 4번 분할 매수한 후 매도 가격은 84,900 / 84,000 / 85,600 / 85,600에서 이루어졌기 때문에 약 7~8% 정도 수익을 낼 수는 있었다. 그 후 95,000 대 까지 오르는 건 알 수 없었기에 RSI 만으로는 고려할 수 없었던 상황이다.
한 종목만 보면 괜찮아 보이지만, 여기엔 크게 두 가지 함정이 있다고 본다.
- 첫 번째 : 여러 번 매수 후 가격이 하락하면 수익 방어가 힘들다는 점이다.
비슷한 가격으로 계속 매수한 것이 보이는데, 위의 경우는 주가가 상승했기 때문에 저점을 잘 잡을 것처럼 보이지만, 반대의 경우도 충분히 나올 수 있다. 따라서 안정적인 투자가 어려워진다.
- 두 번째 : 다중 종목을 모니터링하며 자동매매를 실행했을 때 30선에서 진동하는 종목만 계속 매수해 다른 종목에 투자할 수 있는 현금이 부족할 수 있다는 점이다.
네 번의 매수로 1회 매매를 100만 원으로 잡았다면 총 400만원 만큼 보유하게 되는데, 다중 종목을 매매하려 할 때 한 종목에만 편중되어 버리면 마찬가지로 안정적인 분산투자가 어려워진다.
따라서 위의 사항을 잘 고려한 투자 전략을 세워야 할 것이다. 예를 들어 매매 선을 30, 70이 아닌 28, 72로 수정한다던지, 28 이하로 내려온 후 32 이상될 때 매수한다던지 등의 조금 더 고차원 적인 전략을 만들어야 한다.
다음으로 2022년 10개월의 일 별 매매 횟수를 확인해보자. 코스피 종목 824개를 대상으로 조회했다.
check_df[check_df["buy_tag"]==1].shape
check_df[check_df["sell_tag"]==1].shape
매수 시그널은 3800번, 매도 시그널은 1688번 발생했다. 두 배가 넘게 매수 시그널이 발생한 것이다.
sell_point = check_df.groupby(check_df.index).sum()["sell_tag"]
buy_point = check_df.groupby(check_df.index).sum()["buy_tag"]
plt.subplots(figsize = (14,7))
plt.title("일 별 매매 시그널")
plt.bar(buy_point.index,buy_point,alpha = 0.5,color = "tab:blue")
plt.bar(sell_point.index,sell_point,alpha = 0.5,color = "tab:red")
plt.legend(["buy","sell"])
plt.show()
파란색이 일 별 매수 시그널이고 빨간색이 매도 시그널이다. 일 별 조회이기 때문에 중간중간 공백이 있다. 주말도 일 별에 포함되기 때문이다.
매도 시그널(빨간색)의 경우 사이클이 있지만 전체적으로 넓게 퍼진 것을 볼 수 있다. 반면 매수 시그널(파란색)은 특정 시점에 매우 몰려있는 것을 볼 수 있다. 즉, 특정 시점에 대량의 매수 시그널이 발생을 하고(최대 300개), 이는 시드 머니가 부족할 경우 매수를 못 할 가능성이 높다는 말이 된다.(모니터링하는 종목이 많을 경우)
매매 시그널이 발생한 모든 종목을 무작정 매수하는 것이 아닌 종목 분석을 잘한 후 모니터링 리스트를 잡아야 목적에 맞는 투자를 할 수 있음이 위의 그래프를 통해 나타난다.
코스피의 흐름과 비교하기 위해 KODEX 코스피 etf의 주가를 가져와 이중축으로 그려보았다.
price_data1 = fdr.DataReader("226490","2022")
fig, ax1 = plt.subplots(figsize = (14,7))
ax1.set_ylabel('Price')
ax1.plot(price_data1["Close"],color = "tab:red",alpha = 1)
ax2 = ax1.twinx()
ax2.set_ylabel('Count')
ax2.bar(buy_point.index,buy_point,alpha = 0.5,color = "tab:blue")
plt.title("일 별 매매 시그널")
plt.legend(["buy"])
plt.show()
빨간색이 KODEX 코스피 가격인데 주가가 내려가는 중 상승세로 전환되는 시점에 대량 매수 시그널이 발생함이 보인다. 즉 어떤 종목을 살지는 투자자의 선택이지만, 적어도 매수 시점을 간접적으로 알 수 있는 것이다 물론 지속 하락하는 추세에서는 매도 타이밍을 잘 잡아야 할 것이겠지만.. 반등 후 횡보, 이후 하락 후 횡보를 반복하기 때문이다.
fig, ax1 = plt.subplots(figsize = (14,7))
ax1.set_ylabel('Price')
ax1.plot(price_data1["Close"],color = "tab:red",alpha = 1)
ax2 = ax1.twinx()
ax2.set_ylabel('Count')
ax2.bar(sell_point.index,sell_point,alpha = 0.5,color = "tab:red")
plt.title("일 별 매매 시그널")
plt.legend(["sell"])
plt.show()
매도 시그널을 보면 전체적인 하락이 시작되는 지점에서 대량의 시그널이 발생하는 것을 볼 수 있다. 하락이 이미 시작되었다면 오히려 시그널은 발생빈도가 낮다. 이는 RSI가 선제적으로 시장의 흐름을 알려주고 있다는 것으로도 볼 수 있을 것 같다.
전제적으로 보면 매수 시그널이 매도 시그널에 비해 횟수가 2배 이상 많은 것을 볼 수 있다. 즉, 전략을 설계할 때 이 비율에 대한 매수, 매도 금액을 다르게 가져갈 필요가 있다는 뜻이다. 매수 횟수는 많은데 매도 횟수가 적으면 지속적으로 보유하고 있는 종목과 금액은 클 것이고 추가 매수의 기회를 놓칠 수 있기 때문이다.
물론, KT&G에서 보는 것처럼 추가 상승의 기회도 놓칠 수 있지만, 주식은 무릎에서 사서 어깨에서 팔라고 하지 않는가. 욕심부리지 말고 마음을 비우고 접근하는 것이 중요할 것 같다.
이번 글을 통해 RSI 매매 횟수에 대한 간단히 분석해 보았다. 글을 쓰면서 RSI 값 기준의 30, 70선을 이용한 매매 전략뿐 아니라 횟수로도 시장의 흐름을 대략적으로 파알 할 수 있겠다고 생각이 들었다.
또한, 매수/매도 시그널 발생 횟수도 다르기 때문에 비율에 따라 금액을 정하는 것이 안정성을 높일 수 있을 것 같다.
전략을 설계하면서 궁금했던 사항을 간단히 풀어보았고, 설계하면서 조금 더 깊게 분석하고 글로 남기겠다.
'개발일지' 카테고리의 다른 글
10. 투자지표를 활용한 매매 시점 모니터링 - PDF Reporting (0) | 2022.11.19 |
---|---|
9. 투자지표를 활용한 매매 시점 모니터링 - RSI 종목 추천 (0) | 2022.11.18 |
7. 투자지표를 활용한 매매 시점 모니터링 - 다중 종목 벡테스팅 (0) | 2022.11.10 |
6. 투자지표를 활용한 매매 시점 모니터링 - 손절선 (0) | 2022.11.09 |
5. 투자지표를 활용한 매매 시점 모니터링 - Kospi 종목 벡테스팅 (0) | 2022.11.08 |
댓글