원자재 지수와 주가의 상관관계 분석

2022-01-29 • quant금융데이터분석, 원자재, gsci, 상관관계 • 3 min read

이번 포스트에서는 대표적인 원자재 지수인 S&P GSCI와 주식 종목 주가와의 상관관계를 분석해봅니다. 다음 코드 블록은 종목코드 데이터, 원자재 지수 데이터를 불러오는 부분입니다. 데이터는 퀀티랩 네이버 카페금융데이터 메뉴에서 공유드립니다.

이번 포스트에서는 대표적인 원자재 지수인 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']))

1 2 3 4 5

주로 소형 제조업 위주로 랭킹되는 것을 볼 수 있습니다.

다음으로 역관계로 상관관계가 높은 종목을 랭킹하여 가시화합니다.

# 역 상관관계 높은 종목 가시화
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']))

6 7 8 9 10

주로 연구 위주의 중소형주가 상위랭킹되는 것을 볼 수 있습니다.

데이터 받아가셔서 다양하게 분석해 보시기 바랍니다.