주식차트에서 지지선과 저항선이라는 용어가 있습니다. 차트로 보면 바로 아실 텐데요, 굳이 풀어서 설명하자면 아래와 같습니다.
지지선 Support Level |
○ 주식이 하락하다가 너무 하락이 됐다고 느껴졌는지, 어느 가격대에서 갑자기 매수물량이 대거 등장하면서 더 이상 하락하는 경향을 막아주는 가격대 |
저항선 Resistance Level |
○ 주식이 상승하다 너무 상승이 크다고 생각됐는지, 어느 가격대에서 갑자기 매도물량이 쏟아져 나오며 더 이상 상승하는 경향을 막는 가격대 |
예를 들어 제가 가지고 있는 국동(005320) 주식을 보시죠. 차트는 아래와 같습니다.
혹시 지지선이 보이시나요? 바로 아래와 같습니다.
하락할만 하면 다시 매수세가 쳐들어와 가격이 반전되고, 재차 하락하다 그 레벨까지 주가가 떨어지면 다시 주가가 상승을 합니다. 그 주가 레벨을 "지지" 해주는 것이죠. 이제 국동(005320)의 차트 범위를 약 2년으로 확장하여 보면 아래와 같습니다.
넓은 범위를 보니 저항이 되는 부분도 살짝 보이네요. 내친김에 지지선도 하나 더 찾아보겠습니다.
저는 국동 매매를 통해 한 번은 쪽박, 한번은 약수익을 얻었습니다. 순전히 지지선, 저항선으로만 주가를 판단하는 우를 범하였었죠. 제 매수 타이밍을 한번 볼까요?
첫 번째 매수에서는 지지선 부근의 가격에서 진입하여 저항선까지의 상승을 노렸습니다. 결과는 대폭망. 두 번째 진입에서는 그래도 지지선을 잘 버티며 올라주고 있네요.
주식이라는 것이 매수와 매도의 힘겨루기로 가격이 결정이 됩니다. 느끼기에 주식의 가격은 그 기업의 건전성이나 체력 등으로 결정되는 진정한 가치와 상관이 없습니다(물론 오랜 기간의 주가 움직임은 결국 그 회사의 진정한 가치로 수렴하겠지만요.) 차트를 보면 그 투자자들의 매수 심리와 매도 심리를 얼추 알 수 있습니다.
이제 좀 조악하지만, 주식의 지지선과 저항선을 찾는 코딩을 해보도록 하겠습니다.
python code
import pandas as pd
import numpy as np
import yfinance
from mpl_finance import candlestick_ohlc
import mplfinance
import matplotlib.dates as mpl_dates
import matplotlib.pyplot as plt
import datetime
from dateutil.relativedelta import relativedelta
import FinanceDataReader as fdr
observation_date = 5
def is_Support(df, i):
# c1 = df.Low[i] < df.Low[i - 1] < df.Low[i - 2] < df.Low[i - 3]
# c2 = df.Low[i] < df.Low[i + 1] < df.Low[i + 2] < df.Low[i + 3]
# return c1 & c2
if df.Low[i] == np.min(df.Low[i - observation_date:i + observation_date + 1]):
return True
else:
return False
def is_Resistance(df, i):
# c1 = df.High[i] > df.High[i - 1] > df.High[i - 2] > df.High[i - 3]
# c2 = df.High[i] > df.High[i + 1] > df.High[i + 2] > df.High[i + 3]
# return c1 & c2
if df.High[i] == np.max(df.High[i - observation_date:i + observation_date + 1]):
return True
else:
return False
if __name__ == '__main__':
plt.rcParams['figure.figsize'] = [12, 7] # rcParam을 활용하여 그래프의 기본값(크기, 선의 색, 두께 등)을 설정할 수 있다.
# plt.rcParams['axes.grid'] = True
# rc를 이용해 graph의 font를 확인할 수 있다.
plt.rc('font', size=10)
end_date = datetime.datetime.today()
start_date = end_date - relativedelta(years=1)
stk_code = '005930'
# stk_code = '065770'
df = load_data(stk_code, start_date, end_date)
df['Date'] = pd.to_datetime(df.index)
df['Date'] = df['Date'].apply(mpl_dates.date2num)
df = df.loc[:, ['Date', 'Open', 'High', 'Low', 'Close']]
# date2num : Convert datetime objects toMatplotlib
s = np.mean(df.High - df.Low)
levels_support = []
levels_resistance = []
for i in range(2, df.shape[0] - 3):
if is_Support(df, i):
l = df.Low[i]
if np.sum([abs(l - x[1]) < s * 2 for x in levels_support]) == 0:
levels_support.append((i, l))
elif is_Resistance(df, i):
l = df.High[i]
if np.sum([abs(l - x[1]) < s * 2 for x in levels_resistance]) == 0:
levels_resistance.append((i, l))
fig, ax = plt.subplots()
candlestick_ohlc(ax, df.values, width=0.6, \
colorup='red', colordown='blue', alpha=0.8)
date_format = mpl_dates.DateFormatter('%y/%b/%d')
ax.xaxis.set_major_formatter(date_format)
fig.autofmt_xdate()
fig.tight_layout()
for i, level in enumerate(levels_support):
label_name = 'support line' if i == 0 else None
plt.hlines(level[1], xmin=df['Date'][level[0]], xmax=max(df['Date']), colors='silver', label=label_name)
for i, level in enumerate(levels_resistance):
label_name = 'resistance line' if i == 0 else None
plt.hlines(level[1], xmin=df['Date'][level[0]], xmax=max(df['Date']), colors='skyblue', label=label_name)
plt.legend()
plt.show()
간략히 알아보겠습니다.
def is_Support(df, i): # 지지점을 찾기
# 아래는 i 번째 저점 데이터가 향후 3일, 과거 3일 중 아래로 볼록 한 모양으로 가장 작은 점 찾기
# c1 = df.Low[i] < df.Low[i - 1] < df.Low[i - 2] < df.Low[i - 3]
# c2 = df.Low[i] < df.Low[i + 1] < df.Low[i + 2] < df.Low[i + 3]
# return c1 & c2
# i는 date에 대한 index이고
# 시고저종 데이터중 저가를 대상으로
# i-5일, i+5일 사이에서 가장 저점이 i날인 경우 그날이 지지되는 날이라고 판단
if df.Low[i] == np.min(df.Low[i - observation_date:i + observation_date + 1]):
return True
else:
return False
def is_Resistance(df, i): # 저항점 찾기
# i번째 고가 데이터가 위로 볼록한 모양으로 향후 3일, 과거 3일 중 최대일 때,
# 하지만 주석 처리
# c1 = df.High[i] > df.High[i - 1] > df.High[i - 2] > df.High[i - 3]
# c2 = df.High[i] > df.High[i + 1] > df.High[i + 2] > df.High[i + 3]
# return c1 & c2
# i 번째 고가 데이터가 향후 5일, 과거 5일 중 가장 높은 점일 때
# 그 점을 저항점이라고 판단함
if df.High[i] == np.max(df.High[i - observation_date:i + observation_date + 1]):
return True
else:
return False
if __name__ == '__main__':
plt.rcParams['figure.figsize'] = [12, 7] # rcParam을 활용하여 그래프의 기본값(크기, 선의 색, 두께 등)을 설정할 수 있다.
# plt.rcParams['axes.grid'] = True # chart에 간격선(grid)을 넣을 것인지 아닌지
# rc를 이용해 graph의 font를 확인할 수 있다.
plt.rc('font', size=10)
end_date = datetime.datetime.today() # 데이터 조회 종료일을 오늘로
start_date = end_date - relativedelta(years=1) # 데이터 조회 시작일은 오늘부터 1년전
stk_code = '005930' # 삼성전자 주식(005930)
# stk_code = '065770' # CS 주식(065770)
df = load_data(stk_code, start_date, end_date) # FinanceDataReader 라이브러리로 데이터 load
df['Date'] = pd.to_datetime(df.index) # dataframe에 Date칼럼 만들고 index 복사
df['Date'] = df['Date'].apply(mpl_dates.date2num) # date 를 숫자로 변환하는 함수 적용
df = df.loc[:, ['Date', 'Open', 'High', 'Low', 'Close']] # df 중에서 Date 및 시고저종 column 추출
# date2num : Convert datetime objects toMatplotlib
s = np.mean(df.High - df.Low) # 아래 구할 지지,저항선이 번잡하게 나타나는 것을 방지하는 목적
# 1년 시고저종데이터의 고점과 저점차이의 평균을 s라 함
levels_support = [] # 지지 레벨을 담을 list
levels_resistance = [] # 저항 레벨을 담을 list
for i in range(2, df.shape[0] - 3):
if is_Support(df, i): # 만일 i가 지지점으로 판단되면
l = df.Low[i] # l = i번째 날의 저가
if np.sum([abs(l - x[1]) < s * 2 for x in levels_support]) == 0:
# 그 저가가 이미 구한 지지점들과과 각 차이가 2s보다 작지 않다면
# 즉 전단계에서 구한 지지레벨들과 오밀조밀 하지 않다면
levels_support.append((i, l)) # 지지점으로 인정하고 level_support list에 담음
elif is_Resistance(df, i): # 만일 i가 저항점으로 판단되면
l = df.High[i] # i번째 날의 고가를 l이라 두고
if np.sum([abs(l - x[1]) < s * 2 for x in levels_resistance]) == 0:
# 그것이 기존에 구한 다른 저항점들과 거리가 2s 보다 큰 경우 발생하면
levels_resistance.append((i, l))
# 그 날의 고가를 저항점으로 인식하고 level_resistance에 담음
fig, ax = plt.subplots()
candlestick_ohlc(ax, df.values, width=0.6, \
colorup='red', colordown='blue', alpha=0.8) # ohlc 차트를 그림
date_format = mpl_dates.DateFormatter('%y/%b/%d')
ax.xaxis.set_major_formatter(date_format)
fig.autofmt_xdate()
fig.tight_layout()
for i, level in enumerate(levels_support): # 각 지지선을 hline을 써서 chart 에 표기
label_name = 'support line' if i == 0 else None
plt.hlines(level[1], xmin=df['Date'][level[0]], xmax=max(df['Date']), colors='silver', label=label_name)
for i, level in enumerate(levels_resistance): # 각 저항선을 hlines 을 써서 chart에 표시
label_name = 'resistance line' if i == 0 else None
plt.hlines(level[1], xmin=df['Date'][level[0]], xmax=max(df['Date']), colors='skyblue', label=label_name)
plt.legend()
plt.show()
참고로
2022.07.16 - [주식분석/Quant 분석(프로그래밍)] - 주식 차트 그리기 #2: candlestick_ohlc 시고저종 봉차트
에서 주식 캔들차트 그리는 법을 소개해 놨습니다.
이제 결과를 보면
삼성전자(005930)의 지지선/저항선
CS (065770) 의 지지선/저항선
어떻습니까? 지지/저항선으로 보이시나요?
지지선/저항선을 찾는 하나의 로직일 뿐, 다른 좋은 방법이 많을 것으로 판단됩니다. 참고로 로직 중 일부는 Gianluca Malato 라는 블로거의 코드에서 차용했습니다.
'주식분석 > Quant 분석(프로그래밍)' 카테고리의 다른 글
반응형 그래프와 티스토리에 붙이기 (0) | 2023.03.09 |
---|---|
기술적 지표 #1. AB Ratio (0) | 2023.03.08 |
주식 데이터 불러오기 : FinanceDataReader 라이브러리 (0) | 2023.03.02 |
주식 차트 그리기 #2: candlestick_ohlc 시고저종 봉차트 (0) | 2022.07.16 |
주식 차트 그리기 #1 : mplfinance (0) | 2022.07.08 |
댓글