원자재 지수와 주가의 상관관계 분석
이번 포스트에서는 대표적인 원자재 지수인 S&P GSCI와 주식 종목 주가와의 상관관계를 분석해봅니다. 다음 코드 블록은 종목코드 데이터, 원자재 지수 데이터를 불러오는 부분입니다. 데이터는 퀀티랩 네이버 카페의 금융데이터
메뉴에서 공유드립니다.
- 종목코드: https://cafe.naver.com/quantylab/124
- GSCI: https://cafe.naver.com/quantylab/125
- 종목 일봉차트: https://cafe.naver.com/quantylab/123
이번 포스트에서는 대표적인 원자재 지수인 S&P GSCI와 주식 종목 주가와의 상관관계를 분석해봅니다. 다음 코드 블록은 종목코드 데이터, 원자재 지수 데이터를 불러오는 부분입니다. 데이터는 퀀티랩 네이버 카페의 금융데이터
메뉴에서 공유드립니다.
# 종목코드 데이터 준비
import json
with open('../../../data/stockcodes_20220128.json', encoding='utf-8') as f:
stockcodes = json.load(f)
stockcodes
[['082740', 'HSD엔진'], ['001390', 'KG케미칼'], ['011070', 'LG이노텍'], ['002360', 'SH에너지화학'], ['001740', 'SK네트웍스'], ['071970', 'STX중공업'], ['024070', 'WISCOM'], ['011420', '갤럭시아에스엠'], ['267290', '경동도시가스'], ['002240', '고려제강'], ['001290', '상상인증권'], ['014530', '극동유화'], ['214330', '금호에이치티'], ['013700', '까뮤이앤씨'], ['090350', '노루페인트'], ['005250', '녹십자홀딩스'], ['004440', '삼일씨엔에스'], ['014160', '대영포장'], ['003090', '대웅'], ['003220', '대원제약'], ['002880', '대유에이텍'], ['001620', '케이비아이동국실업'], ['023450', '동남합성'], ['004140', '동방'], ['000640', '동아쏘시오홀딩스'], ['225330', '씨엠에스에듀'], ['101240', '씨큐브'], ['047920', 'HLB제약'], ['013990', '아가방컴퍼니'], ['052710', '아모텍'], ...]
# 원자재 데이터 준비
import pandas as pd
df_gsci = pd.read_csv('../../../data/gsci_20220128.csv', converters={'date': str})
df_gsci
date | close | diff | diffratio | high | low | open | volume |
---|---|---|---|---|---|---|---|
20150102 | 414.9583 | -3.177835 | -0.0076 | 421.5643 | 412.5496 | 418.1225 | 0 |
20150105 | 404.6091 | -10.332034 | -0.0249 | 414.9583 | 403.7641 | 414.9583 | 0 |
20150106 | 397.9523 | -6.676373 | -0.0165 | 406.4719 | 396.1576 | 404.6091 | 0 |
20150107 | 396.6795 | -1.273449 | -0.0032 | 400.6534 | 392.2534 | 397.9523 | 0 |
20150108 | 397.1010 | 0.436331 | 0.0011 | 399.5170 | 393.1882 | 397.2257 | 0 |
... | ... | ... | ... | ... | ... | ... | ... |
20220121 | 608.8819 | -2.568090 | -0.0042 | 611.4234 | 599.3347 | 611.4234 | 0 |
20220124 | 601.5777 | -7.306612 | -0.0120 | 612.6561 | 595.1512 | 608.8819 | 0 |
20220125 | 611.0378 | 9.445007 | 0.0157 | 611.3097 | 601.1267 | 601.5777 | 0 |
20220126 | 619.5484 | 8.493661 | 0.0139 | 621.5063 | 608.4988 | 611.0378 | 0 |
20220127 | 616.7431 | -2.787889 | -0.0045 | 623.2471 | 613.9215 | 619.5484 | 0 |
다음은 종목 일봉 차트와 원자재 지수의 상관관계를 구합니다. 여기서 사용한 상관분석 방법은 피어슨 상관분석 입니다. 피어슨은 상관계수가 -1
에서 1
사이의 값으로, 1에 가까울수록 정관계, -1에 가까울수록 역관계임을 의미합니다.
# 종목 데이터 준비
# 종목과 원자재 상관관계 저장
from scipy.stats import pearsonr
from tqdm import tqdm
df_corr = pd.DataFrame()
for code, name in tqdm(stockcodes):
data = {'code': code, 'name': name}
df_stockcandles_day = pd.read_csv(
f'../../../data/stockcandles_day_20220128/stockcandles_day_{code}_{name}_20220128.csv',
converters={'date': str}
)
start_date = df_stockcandles_day.iloc[0]['date']
end_date = df_stockcandles_day.iloc[-1]['date']
_df_gsci = df_gsci[(df_gsci['date'] >= start_date) & (df_gsci['date'] <= end_date)]
_df = pd.merge(df_stockcandles_day, _df_gsci, how='left', on='date', suffixes=['_stock', '_commodity'])
_df = _df.dropna()
if len(_df) < 20:
continue
corr, p = pearsonr(_df['close_stock'], _df['close_commodity'])
if p <= 0.05:
data['gsci'] = corr
else:
data['gsci'] = 0
df_corr = df_corr.append(data, ignore_index=True)
columns = df_corr.columns.tolist()
columns.remove('code')
columns.remove('name')
columns = ['code', 'name'] + columns
df_corr = df_corr[columns]
df_corr
code | name | gsci |
---|---|---|
082740 | HSD엔진 | 0.697773 |
001390 | KG케미칼 | 0.771450 |
011070 | LG이노텍 | 0.650439 |
002360 | SH에너지화학 | -0.084560 |
001740 | SK네트웍스 | -0.138996 |
... | ... | ... |
298870 | 케이티비네트워크 | -0.954783 |
400840 | 하이제7호스팩 | 0.000000 |
397880 | 교보11호스팩 | 0.000000 |
396770 | 엔에이치스팩22호 | -0.438219 |
400560 | 하나금융20호스팩 | 0.000000 |
이렇게 종목 일봉 차트와 GSCI의 상관계수를 구하고 다음과 같이 후처리합니다.
# NaN 제거
df_corr2 = df_corr.dropna().copy()
# 데이터 저장
df_corr2.to_csv('data/corr.csv', index=False)
# 데이터 불러오기
str_columns = ['code', 'name']
df_corr2 = pd.read_csv('data/corr.csv', converters={k: lambda x: str(x) for k in str_columns})
먼저 NaN을 제거하고 데이터를 저장합니다. 이 데이터도 퀀티랩 네이버 카페에 올려 놓겠습니다.
다음과 같이 스팩과 리츠 종목은 제거하고 상관관계가 높은 종목을 확인합니다.
# 스팩, 리츠 제외
df_corr3 = df_corr2[~(df_corr2['name'].str.endswith('스팩') | df_corr2['name'].str.endswith('리츠'))]
먼저 정관계로 상관관계가 높은 종목을 랭킹하여 가시화합니다.
# 상관관계 높은 종목 가시화
from quantylab.common import viz
for idx, row in df_corr3.sort_values(by='gsci', ascending=False).head(n=5).iterrows():
df_stockcandles_day = pd.read_csv(
'../../../data/stockcandles_day_20220128/stockcandles_day_{}_{}_20220128.csv'.format(row['code'], row['name']),
converters={'date': str}
)
start_date = df_stockcandles_day.iloc[0]['date']
end_date = df_stockcandles_day.iloc[-1]['date']
_df_gsci = df_gsci[(df_gsci['date'] >= start_date) & (df_gsci['date'] <= end_date)]
_df = pd.merge(df_stockcandles_day, _df_gsci, how='left', on='date', suffixes=['_stock', '_commodity'])
_df = _df.dropna().copy().reset_index(drop=True)
print('{} {} {}'.format(row['name'], row['max_commodity'], row['max_corr']))
viz.show_notebook(viz.get_multchart(_df['date'], _df['close_stock'], _df['close_commodity'], label1=row['name'], label2=row['max_commodity']))
주로 소형 제조업 위주로 랭킹되는 것을 볼 수 있습니다.
다음으로 역관계로 상관관계가 높은 종목을 랭킹하여 가시화합니다.
# 역 상관관계 높은 종목 가시화
from quantylab.common import viz
for idx, row in df_corr3.sort_values(by='gsci', ascending=True).head(n=5).iterrows():
df_stockcandles_day = pd.read_csv(
'../../../data/stockcandles_day_20220128/stockcandles_day_{}_{}_20220128.csv'.format(row['code'], row['name']),
converters={'date': str}
)
start_date = df_stockcandles_day.iloc[0]['date']
end_date = df_stockcandles_day.iloc[-1]['date']
_df_gsci = df_gsci[(df_gsci['date'] >= start_date) & (df_gsci['date'] <= end_date)]
_df = pd.merge(df_stockcandles_day, _df_gsci, how='left', on='date', suffixes=['_stock', '_commodity'])
_df = _df.dropna().copy().reset_index(drop=True)
print('{} {} {}'.format(row['name'], row['max_commodity'], row['max_corr']))
viz.show_notebook(viz.get_multchart(_df['date'], _df['close_stock'], _df['close_commodity'], label1=row['name'], label2=row['max_commodity']))
주로 연구 위주의 중소형주가 상위랭킹되는 것을 볼 수 있습니다.
데이터 받아가셔서 다양하게 분석해 보시기 바랍니다.