-
[키움API]python 샤프지수를 이용한 종목선정 2금융퀀트/(퀀트)증권사API활용(키움) 2024. 1. 28. 16:28반응형
종목별 샤프지수 분석과 UI 변경
샤프지수의 정의
샤프지수는 아래 식으로 나타낼 수 있다.(샤프지수(Sharpe Ratio): 얼마나 덜 쫄리게 많이 벌었나? 참조)
샤프지수 = (투자자산의 수익률 - 기초수익률 ) / 투자자산의 변동성
우리는 [키움API]python 샤프지수를 이용한 종목선정1: 코스피 종목 종가데이터 입수에서 종목별 종가를 입수했기 때문에 종목별 일일 수익률과 계산된 일일 수익률의 표준편차로 수익률의 변동성을 알 수 있다. 그리고 기초 수익률은 해당 종목이 아닌 예금 등 무위험 자산에 투자했을 때 얻을 수 있는 수익률인데 현재 3년 국고채 금리인 3.3% 정도로 잡으면 될 것 같다. 주의해야 할 점은 일일 수익률과 일일 표준편차를 계산했기 때문에 연 금리인 3.3%를 일일 금리로 환산해야 한다는 것이다.((1+3.3%)^(1/365) -1 식을 써서 환산하면 된다. 자세한 내용은 금리의 기간/복리와 단리를 알아보자 참조) 다만 종목별 샤프지수의 상대적인 비교가 중요하기 때문에 종목별 샤프지수 계산에 공통값으로 적용되는 기초수익률 자체는 별 의미는 없다.
화면상 입력변수 추가
무한한 기간을 대상으로 할 수 없기 때문에 종목별 샤프지수 분석 전에 분석 기간을 먼저 정해야하고, 큰 의미는 없지만 무위험 이자율도 분석 시점에 정해줘야 한다. 결국 입력 변수를 투입하는 화면은 아래 그림 1과 같이 수정할 수 있다.
코스피 종가 데이터 불러오기: loadtimeseriesdata
이제 [키움API]python 샤프지수를 이용한 종목선정1: 코스피 종목 종가데이터 입수에서 만든 코스피 종가 데이터를 불러오는 함수만 만들면 기본적인 준비는 끝난다. 데이터를 불러오는 함수는 간단하게 테이블명과 시작일과 종료일을 list 형태로 받아서 날짜를 기준으로 데이터를 가져오는 쿼리와 pandas 의 read_sql 함수를 조합하여 데이터를 DataFrame 형식으로 만들어내는 방식으로 아래와 같다.
#SQLhandle import pymysql import sqlalchemy as db import pandas as pd pymysql.install_as_MySQLdb() class SQLhandle: def __init__(self): ...(생략)... def loadtimeseriesdata(self, tablename: str, fromtodates: list): query = f''' SELECT 일자, 종목코드, 현재가 FROM {tablename} WHERE 일자 BETWEEN {fromtodates[0]} AND {fromtodates[1]} ORDER BY 종목코드, 일자; ''' data = pd.read_sql(query, con=self.engine) return data
데이터를 불러오는 이 함수는 MySQL을 통한 기능이기 때문에 [키움API]파이썬 주식 종목별 종가정보 불러오기5: UI파일 화면구성(Qt Designer) 및 프로그램module과 CLASS구성에서 그린 아래 그림 2의 프로그램 구조도에서 sqlhandle.py 모듈의 SQLhandle 클래스에 추가한다.
개별종목 샤프지수 비교해서 상위 10개 종목 추출: gethighsharperatio
이제 추출된 데이터를 바탕으로 샤프지수를 계산하고 상위 10 개 종목만 뽑아내서 그림 1 화면 상 텍스트 상자에 보여주는 기능만 구현하면 된다. 먼저, 화면에서 변수들을 입수하고, pandas DataFrame 클래스에 내장된 pct_change 함수를 이용해서 일일 수익률을 구해서 "수익률"컬럼을 만든다. 그 뒤 종목코드별로 묶어서(groupby("종목코드")) 평균과 표준편차를 구하고, 샤프지수까지 구해서 ["종목코드", "일일수익률평균", "일일표준편차", "샤프지수"]라는 컬럼을 가진 df_sharperatio 라는 DataFrame을 만든다. 그리고 Utils 클래스의 loadkospilist 함수를 사용해서 ["종목코드", "종목명"]라는 컬럼을 가진 df_name이라는 DataFrame을 하나 더 만든다. 마지막으로 두 개의 데이터프레임을 "종목코드"를 기준으로 합쳐주면, ["종목코드", "종목명", "일일수익률평균", "일일표준편차", "샤프지수"] 컬럼을 가진 데이터프레임을 얻을 수 있다.
얻은 데이터프레임 중 샤프지수가 큰 상위 10개의 종목에 대해서 postdfresult 라는 함수를 사용해서 그리드 형식으로 화면의 "txt_result"라는 텍스트 상자에 보여준다. postdfresult 함수에는 tabulate 라이브러리가 사용됐는데, 아나콘다 프롬프트에서 pip install tabulate 이라는 명령어로 설치하면 된다. 이 라이브러리는 표 형식의 데이터를 그리드로 표시해주는 기능을 한다.
#UIhandle from PyQt5.QtWidgets import * import time import pandas as pd from tabulate import tabulate from kiwoomapi import KIWOOMapi from apihandle import APIhandle from sqlhandle import SQLhandle from utils import Utils class UIhandle(QWidget): def __init__(self, ocx: object, mainui): super().__init__() self.mainui = mainui self.ocx = ocx self.api = KIWOOMapi(ocx) self.handle = APIhandle(ocx) self.sql = SQLhandle() self.utils = Utils() self.timer = time ...(생략)... # 데이터 프레임을 그리드로 텍스트 상자에 보여주는 함수 def postdfresult(self, data: pd.DataFrame): # 데이터를 보여줄 텍스트 상자를 변수화 txt_result = self.mainui.findChild(QTextEdit, "txt_result") # 결과값을 tabulate 함수를 써서 그리드 형태로 table_str이라는 변수에 저장 table_str = tabulate(data, headers='keys', tablefmt='grid', showindex=False) # 결과값을 텍스트 상자에 표시 txt_result.setPlainText(table_str) # UI에서 날짜값을 받아오는 함수 def getdate(self, dateeditid: str): date = self.mainui.findChild(QDateEdit, dateeditid) return date ...(생략)... # UI의 QDoubleSpinBox에서 값을 받아오는 함수 위 그림 1의 기초수익률 칸 def getdoublespinboxvalue(self, spinboxeditid: str): spinbox = self.mainui.findChild(QDoubleSpinBox, spinboxeditid) return spinbox.value() ...(생략)... # 샤프지수 값을 구해서 상위 10개를 뽑아내는 함수 def gethighsharperatio(self): # 샤프지수를 구할 시작일자와 마지막일자를 받아오기 fromdate = self.getdate("date_analfrom").date().toString("yyyyMMdd") todate = self.getdate("date_analto").date().toString("yyyyMMdd") # 날짜를 리스트에 저장 fromtodates = [fromdate, todate] # 시작일자와 마지막일자에 해당하는 "stockdailychart"에 저장된 모든 종가정보를 입수 df = self.sql.loadtimeseriesdata("stockdailychart", fromtodates) # 무위험수익률 입수 riskfreerate = int(self.getdoublespinboxvalue("doubleSpinBox_rfr")) # 종목코드별로(GROUP BY) 현재가의 일일 수익률(pct_change)을 구해서 수익률컬럼에 저장 df['수익률'] = df.groupby('종목코드')['현재가'].pct_change() # 수익률의 평균과 표준편차 구하기 dailyreturn = df.groupby('종목코드')['수익률'].mean() dailystdev = df.groupby('종목코드')['수익률'].std() # 무위험수익률을 일일 수익률로 변환 dailyrfr = (1 + riskfreerate)**(1/365) - 1 # 샤프지수 계산식에 따른 샤프지수 계산 dailyspr = (dailyreturn - dailyrfr) / dailystdev # 결과를 df_sharperatio 데이터프레임에 저장 df_sharperatio = pd.DataFrame({ "종목코드":dailyreturn.index, "일일수익률평균":dailyreturn.values, "일일표준편차":dailystdev.values, "샤프지수":dailyspr.values }) # 코스피 종목의 이름을 갖고오기 위해 Utils 클래스에(상단에서 self.utils = Utils()로 # 객체화 함) loadkospilist 함수로 데이터 갖고옴 dfstocknames = self.utils.loadkospilist() # dfstocknames 정보로 "종목코드", "종목명"으로 이루어진 데이터프레임 구성 df_name = pd.DataFrame(data=dfstocknames, columns=["종목코드","종목명"]) # df_sharperatio의 "종목코드" 컬럼을 기준으로 dfstocknames 데이터 붙이기 df = pd.merge(df_sharperatio, df_name, how="left", on=["종목코드"]) # 샤프지수가 높은 순서대로 정렬 df = df.sort_values(by="샤프지수", ascending=False) # 컬럼 재정의 df = df[["종목코드", "종목명", "일일수익률평균", "일일표준편차", "샤프지수"]] # 상위 10개 만 뽑아서 postdfresult 함수를 사용해서 화면에 보여주기 self.postdfresult(df.head(10))
메인화면 설정 변경
마지막으로 main 화면에 아래와 같이 버튼과 날짜입력란을 변수로 설정해 주면 모든 기능이 구현된다.
import sys from PyQt5.QtWidgets import * from PyQt5.QAxContainer import * from PyQt5.QtCore import QDate from PyQt5 import uic from uihandle import UIhandle form_class = uic.loadUiType("UI 파일의 경로 입력")[0] class KiwoomAPIForm(QMainWindow, form_class): def __init__(self): ...(생략)... def initsetting(self): yesterday = QDate.currentDate().addDays(-1) self.findChild(QDateEdit, "date_base").setDate(yesterday) # 샤프지수 분석 시작일자 ~ 종료일자 칸 설정: 데이터 입수시 2021-08-12 데이터부터 # 2024-01-19 데이터 까지 입수해서 기본설정값을 20210812, 20240119로 설정함 self.findChild(QDateEdit, "date_analfrom").setDate(QDate.fromString("20210812", "yyyyMMdd")) self.findChild(QDateEdit, "date_analto").setDate(QDate.fromString("20240119", "yyyyMMdd")) self.buttongroup.addButton(self.btn_login, 1) self.buttongroup.addButton(self.btn_dataget, 2) # 함수와 연결하기 위한 버튼 그룹 추가 위 그림 1에 따라 종목추천 버튼의 오브젝트 명은 # btn_recommend 임 self.buttongroup.addButton(self.btn_recommend, 3) def buttonfunction(self, button): buttonid = self.buttongroup.id(button) if buttonid == 1: self.ui.apilogin() elif buttonid == 2: self.ui.gettimeseriesdata() # buttonid = 3 즉 btn_recommend 를 눌렀을 때 gethighsharperatio 작동하도록 설정 elif buttonid == 3: self.ui.gethighsharperatio() if __name__ == "__main__": app = QApplication(sys.argv) window = KiwoomAPIForm() window.show() sys.exit(app.exec_())
구현된 기능을 이용해서 2021.08.12 ~ 2024.01.19 일자에 대해서 코스피 종목에 대한 데이터를 수집하여 샤프지수 분석을 하면 아래와 같은 결과를 얻을 수 있다.(역시 에코프로가 1등이다.)
반응형'금융퀀트 > (퀀트)증권사API활용(키움)' 카테고리의 다른 글
[키움API]python 샤프지수를 이용한 종목선정1: 코스피 종목 종가데이터 입수 (0) 2024.01.22 [키움API]파이썬 주식 종목별 종가정보 불러오기6: 데이터 수집시 주의사항 (0) 2024.01.20 [키움API]파이썬 주식 종목별 종가정보 불러오기5: UI파일 화면구성(Qt Designer) 및 프로그램module과 CLASS구성 (2) 2023.12.19 [키움API]파이썬 주식 종가정보 불러오기4: 데이터 DB저장(mysql) (0) 2023.12.06 [키움API]파이썬 주식 종가정보 불러오기3: 전체종목 기간별 종가조회 (2) 2023.12.02