현재 '파이썬으로 구현하는 계량투자'라는 강의를 러닝 스푼즈에서 하고 있는데 수강생들 몇 분이 강환국님의 책에 나온 전략을 구현해 달라고 하여 구현해 봅니다. 사실 기본은 수업에 한 것과 전혀 다르지 않습니다. 데이터 가져와서 필터링하고 정렬하면 돼요. 그게 끝! 우리는 pandas라는 무기를 가지고 있어서 정말 쉽게 할 수 있습니다. 문제는 데이터! 여기서는 퀀트킹님의 카페에 올라오는 데이터를 사용하도록 하겠습니다.
이 포스트에서 구현할 전략은 다음과 같습니다. 이름하여 '행복전략'! (강환국님의 네이밍 센스 재밌네요 ㅎㅎ)
먼저 pandas를 import해 봅시다.
그리고 무엇보다 먼저 재료가 될 데이터를 가져와야겠죠. pandas에 read_excel 함수를 이용하면 언제나처럼 쉽게 데이터를 가져올 수 있습니다. 데이터는 앞에서 말한 것처럼 퀀트킹님의 카페에 무료로 올라오는 데이터를 이용하였습니다. 다만 해당 엑셀 파일의 확장자명이 xlsb인데 이는 read_excel 함수에서 지원을 하지 않으므로 xlsx 확장자로 다시 저장을 해 줬습니다.
위에서 옵션이 많이 들어갑니다. 일단 sheet_name은 우리가 필요한 데이터가 '퀀트데이타' 시트에 있기 때문에 해당 시트를 가져오라고 넣어준 것입니다. skiprows 같은 경우 위에서 2개 행은 제목과 공백 행이라 필요 없기 때문에 이 2개 행을 스킵하라고 넣어 주었습니다. 인덱스는 가져올 데이터(정확히는 데이터 프레임)의 인덱스를 0번째 열(칼럼)인 회사코드로 정해주려고 넣었습니다. 마지막으로 usecols는 해당 시트에 있는 모든 데이터를 쓸게 아니므로 필요한 열(칼럼)들을 지정해 준 것입니다.
하지만 이렇게 데이터를 읽어오면 엄청 오래 걸립니다. 왜냐하면 이 엑셀 데이터가 엄청 무겁기 때문이에요. 그래서 전 그냥 해당 시트의 내용만 다른 엑셀에 아래처럼 복사했습니다. 이렇게 새로운 엑셀 파일 만들어서 저장을 할게요.
저장된 엑셀 파일에서 데이터를 다시 읽어 옵시다.
위에서 엑셀 데이터를 붙여 넣기 할 때 사진처럼 옮겨 붙였기 때문에 그에 맞추어 옵션을 조정해 주었습니다. 이렇게 데이터를 읽어오면 훨씬 빨리 읽어 올 거예요. 이제 데이터 가지고 위에 조건대로 데이터를 만지작 거려 보겠습니다.
일단 PCR 중에 음수가 있는 데이터들을 없애 버리겠습니다. pandas에서 필터링하는 것은 위와 같이 하면 되죠. 그리고 정렬한 다음에 상위 30%인 아이들만 가져오는 코드입니다. 음수 PCR을 없애 데이터에서 길이를 구한 뒤 0.3을 곱해서 대략 30%가 몇 개까지 인지 알아낸 후 거기까지만 가져오면 PCR 하위 30% 선택 완료입니다.
배당성향이 35%에서 75% 사이의 주식들만 가져오는 코드입니다. 이것도 pandas의 필터링 기능을 이용하면 간단합니다.
이것도 쉽습니다. 앞에서처럼 필터링을 줍니다. 너무 간단해서 딱히 설명할 것이 없어 민망하네요;;;
결과는 다음과 같습니다. ( 퀀트킹 데이터 2018.06.08 기준 결과)
마지막으로 정리한 코드입니다.
import pandas as pd
# 퀀트킹 엑셀 데이터에서 퀀트데이터 시트만 따로 복사한 엑셀 파일
data_file = r'C:\Users\JK\Desktop\퀀트데이터.xlsx'
# 데이터 불러오기
data = pd.read_excel(data_file, sheet_name='Sheet1',
index_col=0, usecols='A:G,Z,AH,AW,AY,AZ')
# 음수 PCR 필터링
positive_pcr = data[data['과거\nPCR']>0]
# 하위 30% 저 PCR 선택
low_pcr = positive_pcr.sort_values(by='과거\nPCR')[:int(len(positive_pcr)*0.3)]
# 배당성향 35% ~ 75% 선택
div = low_pcr[low_pcr['배당\n성향\n(%)']>=35]
div = div[div['배당\n성향\n(%)']<=75]
# PBR 1.5보다 작은 거 제외
pbr_filter = div[div['5년평균\nPBR'] >= 1.5]
# 부채비율 150%보다 큰 거 제외
happy = pbr_filter[pbr_filter['보수적\n부채비율\n(%)']<150]