일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- RS-485
- Espressif
- cluster
- homebridge
- 오블완
- Apple
- raspberry pi
- 월패드
- 공모주
- 미국주식
- SK텔레콤
- esp32
- MQTT
- matter
- 해외주식
- 힐스테이트 광교산
- 나스닥
- ConnectedHomeIP
- 홈네트워크
- 현대통신
- Bestin
- 매터
- 파이썬
- Python
- 배당
- 국내주식
- Home Assistant
- 애플
- 티스토리챌린지
- 코스피
- Today
- Total
YOGYUI
공공데이터포털::한국예탁결제원 주식정보서비스 (REST API) 본문
공공데이터포털(data.go.kr)에서 한국예탁결제원이 제공하는 국내 주식시장과 관련된 다양한 정보들을 가져와보자 (KSD 증권정보포털인 SEIBro의 API, api.seibro.or.kr)
1. 공공데이터포털 API 활용신청
데이터 타이틀은 "한국예탁결제원_주식정보서비스", URL은 아래 링크 참고
https://www.data.go.kr/data/15001145/openapi.do
1.1 활용신청
활용신청 버튼을 클릭
1.2. 활용목적 기입
1.3. 상세기능정보 선택
특별한 사유가 아니라면 전부 선택해주자
(서버 과부하를 우려해서 그런가, 일일 트래픽이 기능별로 100회로 한정되어 있다 ㅠ)
1.4. 활용신청
저작자표시 동의 체크박스 클릭 수 활용신청
2. 인증키 확인
[마이페이지 - 오픈API - 개발계정]
신청한 서비스(한국예탁결제원_주식정보서비스) 클릭
개발계정 상세보기에서 인증키를 확인할 수 있다
API 호출시에 사용해야 하니 메모장에 복붙해두자
※중요: 상세기능정보에서 API 호출 테스트를 할 수 있다
만약 아래와 같이 "SERVICE KEY IS NOT REGISTERED ERROR" 결과가 반환된다면 아직 API 활용 신청에 대한 서버 동기화가 이루어지지 않은 것이니, 신청 후 여유롭게 하루정도는 기다려주자
3. 활용 예시 (배당순위조회)
"찬바람이 불면 배당주를 사라"는 투자 격언은 많은 주식 투자자들이 한번은 들어봤을 것 같은데, 정작 배당을 많이 주는 종목이 뭔지는 경제 기사에서 집계해주는 게 아니면 직접 찾아보기가 약간은 번거로웠을텐데 (포털사이트 통계 혹은 증권사 서비스 이용 등) 과연 공공데이터포털의 Open API로는 제대로 된 정보를 얻을 수 있을지 확인해보자
페이지에서 제공하는 API 가이드 문서
를 따라 테스트 코드를 작성해보자
(다른 포스팅 글과 마찬가지로 여기서도 Python을 활용)
한국예탁결제원_주식정보서비스 API의 공통 서비스 URL은
<http://api.seibro.or.kr/openapi/service/StockSvc> 이고 서비스별로 서로 다른 상세주로를 가진다
예를 들어 배당순위조회의 상세 URL은 getDividendRankN1 이므로 호출 API URL은
http://api.seibro.or.kr/openapi/service/StockSvc/getDividendRankN1
이 된다
요청변수 중 필수 파라미터, 옵션 파라미터 등을 참고해서 테스트 코드를 작성해보자
작년 (2020년) 기준으로 모든 시장에 대한 상위 배당률 10개 종목을 쿼리해보자
import requests
url_base = "http://api.seibro.or.kr/openapi/service/StockSvc"
url_spec = "getDividendRankN1"
url = url_base + "/" + url_spec
api_key_utf8 = "Your API Key form data.go.kr"
api_key_decode = requests.utils.unquote(api_key_utf8, encoding='utf-8')
params = {
"serviceKey": api_key_decode,
"rankTpcd": 1,
"year": 2020,
"numOfRows": 10,
"pageNo": 1,
}
response = requests.get(url, params=params)
In [1]: print(response.text)
Out[1]:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><response><header><resultCode>00</resultCode><resultMsg>NORMAL SERVICE.</resultMsg></header><body><items><item><caltotMartTpcd>유가증권시장</caltotMartTpcd><divAmtPerStk>9900</divAmtPerStk><divRateCpri>29.5</divRateCpri><divRatePval>1980</divRatePval><issucoCustno>2345</issucoCustno><korSecnNm>동남합성</korSecnNm><num>1</num><pval>500</pval><secnKacd>보통주</secnKacd><setaccMm>12</setaccMm><setaccMmdd>1231</setaccMmdd><shotnIsin>023450</shotnIsin></item><item><caltotMartTpcd>유가증권시장</caltotMartTpcd><divAmtPerStk>16750</divAmtPerStk><divRateCpri>21.14</divRateCpri><divRatePval>335</divRatePval><issucoCustno>1739</issucoCustno><korSecnNm>서울도시가스</korSecnNm><num>2</num><pval>5000</pval><secnKacd>보통주</secnKacd><setaccMm>12</setaccMm><setaccMmdd>1231</setaccMmdd><shotnIsin>017390</shotnIsin></item><item><caltotMartTpcd>코스닥시장</caltotMartTpcd><divAmtPerStk>3244.52</divAmtPerStk><divRateCpri>19.8</divRateCpri><divRatePval>0</divRatePval><issucoCustno>34462</issucoCustno><korSecnNm>에스앤케이 KDR</korSecnNm><num>3</num><pval>0</pval><secnKacd>보통주</secnKacd><setaccMm>07</setaccMm><setaccMmdd>0731</setaccMmdd><shotnIsin>950180</shotnIsin></item><item><caltotMartTpcd>유가증권시장</caltotMartTpcd><divAmtPerStk>500</divAmtPerStk><divRateCpri>16.2</divRateCpri><divRatePval>100</divRatePval><issucoCustno>811</issucoCustno><korSecnNm>대동전자</korSecnNm><num>4</num><pval>500</pval><secnKacd>보통주</secnKacd><setaccMm>03</setaccMm><setaccMmdd>0331</setaccMmdd><shotnIsin>008110</shotnIsin></item><item><caltotMartTpcd>유가증권시장</caltotMartTpcd><divAmtPerStk>0</divAmtPerStk><divRateCpri>12.8</divRateCpri><divRatePval>7.03835617</divRatePval><issucoCustno>18894</issucoCustno><korSecnNm>바다로19호선박투자회사</korSecnNm><num>5</num><pval>5000</pval><secnKacd>보통주</secnKacd><setaccMm>12</setaccMm><setaccMmdd>1231</setaccMmdd><shotnIsin>155900</shotnIsin></item><item><caltotMartTpcd>코스닥시장</caltotMartTpcd><divAmtPerStk>800</divAmtPerStk><divRateCpri>11.88</divRateCpri><divRatePval>160</divRatePval><issucoCustno>1270</issucoCustno><korSecnNm>리드코프</korSecnNm><num>6</num><pval>500</pval><secnKacd>보통주</secnKacd><setaccMm>12</setaccMm><setaccMmdd>1231</setaccMmdd><shotnIsin>012700</shotnIsin></item><item><caltotMartTpcd>유가증권시장</caltotMartTpcd><divAmtPerStk>1250</divAmtPerStk><divRateCpri>10.9</divRateCpri><divRatePval>25</divRatePval><issucoCustno>354</issucoCustno><korSecnNm>대신증권1우</korSecnNm><num>7</num><pval>5000</pval><secnKacd>우선주</secnKacd><setaccMm>12</setaccMm><setaccMmdd>1231</setaccMmdd><shotnIsin>003545</shotnIsin></item><item><caltotMartTpcd>유가증권시장</caltotMartTpcd><divAmtPerStk>1200</divAmtPerStk><divRateCpri>8.6</divRateCpri><divRatePval>24</divRatePval><issucoCustno>354</issucoCustno><korSecnNm>대신증권</korSecnNm><num>8</num><pval>5000</pval><secnKacd>보통주</secnKacd><setaccMm>12</setaccMm><setaccMmdd>1231</setaccMmdd><shotnIsin>003540</shotnIsin></item><item><caltotMartTpcd>유가증권시장</caltotMartTpcd><divAmtPerStk>900</divAmtPerStk><divRateCpri>8.6</divRateCpri><divRatePval>180</divRatePval><issucoCustno>16786</issucoCustno><korSecnNm>메리츠금융지주</korSecnNm><num>9</num><pval>500</pval><secnKacd>보통주</secnKacd><setaccMm>12</setaccMm><setaccMmdd>1231</setaccMmdd><shotnIsin>138040</shotnIsin></item><item><caltotMartTpcd>유가증권시장</caltotMartTpcd><divAmtPerStk>500</divAmtPerStk><divRateCpri>8.6</divRateCpri><divRatePval>20</divRatePval><issucoCustno>70</issucoCustno><korSecnNm>유수홀딩스</korSecnNm><num>10</num><pval>2500</pval><secnKacd>보통주</secnKacd><setaccMm>12</setaccMm><setaccMmdd>1231</setaccMmdd><shotnIsin>000700</shotnIsin></item></items><numOfRows>10</numOfRows><pageNo>1</pageNo><totalCount>1441</totalCount></body></response>
XML 출력을 보기 좋게 바꿔보자 (BeautifulSoup - prettify)
from bs4 import BeautifulSoup
xml = BeautifulSoup(response.text, "lxml")
print(xml.prettify())
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<html>
<body>
<response>
<header>
<resultcode>00</resultcode>
<resultmsg>NORMAL SERVICE.</resultmsg>
</header>
<items>
<item>
<caltotmarttpcd>유가증권시장</caltotmarttpcd>
<divamtperstk>9900</divamtperstk>
<divratecpri>29.5</divratecpri>
<divratepval>1980</divratepval>
<issucocustno>2345</issucocustno>
<korsecnnm>동남합성</korsecnnm>
<num>1</num>
<pval>500</pval>
<secnkacd>보통주</secnkacd>
<setaccmm>12</setaccmm>
<setaccmmdd>1231</setaccmmdd>
<shotnisin>023450</shotnisin>
</item>
<item>
<caltotmarttpcd>유가증권시장</caltotmarttpcd>
<divamtperstk>16750</divamtperstk>
<divratecpri>21.14</divratecpri>
<divratepval>335</divratepval>
<issucocustno>1739</issucocustno>
<korsecnnm>서울도시가스</korsecnnm>
<num>2</num>
<pval>5000</pval>
<secnkacd>보통주</secnkacd>
<setaccmm>12</setaccmm>
<setaccmmdd>1231</setaccmmdd>
<shotnisin>017390</shotnisin>
</item>
<item>
<caltotmarttpcd>코스닥시장</caltotmarttpcd>
<divamtperstk>3244.52</divamtperstk>
<divratecpri>19.8</divratecpri>
<divratepval>0</divratepval>
<issucocustno>34462</issucocustno>
<korsecnnm>에스앤케이 KDR</korsecnnm>
<num>3</num>
<pval>0</pval>
<secnkacd>보통주</secnkacd>
<setaccmm>07</setaccmm>
<setaccmmdd>0731</setaccmmdd>
<shotnisin>950180</shotnisin>
</item>
<item>
<caltotmarttpcd>유가증권시장</caltotmarttpcd>
<divamtperstk>500</divamtperstk>
<divratecpri>16.2</divratecpri>
<divratepval>100</divratepval>
<issucocustno>811</issucocustno>
<korsecnnm>대동전자</korsecnnm>
<num>4</num>
<pval>500</pval>
<secnkacd>보통주</secnkacd>
<setaccmm>03</setaccmm>
<setaccmmdd>0331</setaccmmdd>
<shotnisin>008110</shotnisin>
</item>
<item>
<caltotmarttpcd>유가증권시장</caltotmarttpcd>
<divamtperstk>0</divamtperstk>
<divratecpri>12.8</divratecpri>
<divratepval>7.03835617</divratepval>
<issucocustno>18894</issucocustno>
<korsecnnm>바다로19호선박투자회사</korsecnnm>
<num>5</num>
<pval>5000</pval>
<secnkacd>보통주</secnkacd>
<setaccmm>12</setaccmm>
<setaccmmdd>1231</setaccmmdd>
<shotnisin>155900</shotnisin>
</item>
<item>
<caltotmarttpcd>코스닥시장</caltotmarttpcd>
<divamtperstk>800</divamtperstk>
<divratecpri>11.88</divratecpri>
<divratepval>160</divratepval>
<issucocustno>1270</issucocustno>
<korsecnnm>리드코프</korsecnnm>
<num>6</num>
<pval>500</pval>
<secnkacd>보통주</secnkacd>
<setaccmm>12</setaccmm>
<setaccmmdd>1231</setaccmmdd>
<shotnisin>012700</shotnisin>
</item>
<item>
<caltotmarttpcd>유가증권시장</caltotmarttpcd>
<divamtperstk>1250</divamtperstk>
<divratecpri>10.9</divratecpri>
<divratepval>25</divratepval>
<issucocustno>354</issucocustno>
<korsecnnm>대신증권1우</korsecnnm>
<num>7</num>
<pval>5000</pval>
<secnkacd>우선주</secnkacd>
<setaccmm>12</setaccmm>
<setaccmmdd>1231</setaccmmdd>
<shotnisin>003545</shotnisin>
</item>
<item>
<caltotmarttpcd>유가증권시장</caltotmarttpcd>
<divamtperstk>1200</divamtperstk>
<divratecpri>8.6</divratecpri>
<divratepval>24</divratepval>
<issucocustno>354</issucocustno>
<korsecnnm>대신증권</korsecnnm>
<num>8</num>
<pval>5000</pval>
<secnkacd>보통주</secnkacd>
<setaccmm>12</setaccmm>
<setaccmmdd>1231</setaccmmdd>
<shotnisin>003540</shotnisin>
</item>
<item>
<caltotmarttpcd>유가증권시장</caltotmarttpcd>
<divamtperstk>900</divamtperstk>
<divratecpri>8.6</divratecpri>
<divratepval>180</divratepval>
<issucocustno>16786</issucocustno>
<korsecnnm>메리츠금융지주</korsecnnm>
<num>9</num>
<pval>500</pval>
<secnkacd>보통주</secnkacd>
<setaccmm>12</setaccmm>
<setaccmmdd>1231</setaccmmdd>
<shotnisin>138040</shotnisin>
</item>
<item>
<caltotmarttpcd>유가증권시장</caltotmarttpcd>
<divamtperstk>500</divamtperstk>
<divratecpri>8.6</divratecpri>
<divratepval>20</divratepval>
<issucocustno>70</issucocustno>
<korsecnnm>유수홀딩스</korsecnnm>
<num>10</num>
<pval>2500</pval>
<secnkacd>보통주</secnkacd>
<setaccmm>12</setaccmm>
<setaccmmdd>1231</setaccmmdd>
<shotnisin>000700</shotnisin>
</item>
</items>
<numofrows>10</numofrows>
<pageno>1</pageno>
<totalcount>1441</totalcount>
</response>
</body>
</html>
각 <item> 태그별로 다음 하위태그들의 정보를 확인할 수 있다
- caltotMartTpcd: 시장구분 (유가증권/코스닥/K-OTC/코넥스/기타비상장)
- divAmtPerStk: 주당배당금 (단위: 원)
- divRateCpri: 시가배당률 (단위: %)
- divRatePval: 액면가배당율 (단위: %)
- issucoCustno: 발행회사번호
- korSecnNm: 국문 종목명
- num: 배당 순위
- pval: 액면가 (단위: 원)
- secnKacd: 주식종류 (보통주/우선주)
- setaccMm: 결산월
- setaccMmdd: 결산월일
- shotnIsin: 단축코드 (6자리, 주식거래앱 등에서 활용)
이제 XML의 아이템들을 pandas 데이터프레임으로 변환해보자
import pandas as pd
items = xml.find("items")
item_list = []
for item in items:
item_dict = {
'caltotmarttpcd': item.find("caltotmarttpcd").text.strip(),
'divamtperstk': float(item.find("divamtperstk").text.strip()),
'divratecpri': float(item.find("divratecpri").text.strip()),
'divratepval': float(item.find("divratepval").text.strip()),
'issucocustno': item.find("issucocustno").text.strip(),
'korsecnnm': item.find("korsecnnm").text.strip(),
'num': int(item.find("num").text.strip()),
'pval': int(item.find("pval").text.strip()),
'secnkacd': item.find("secnkacd").text.strip(),
'setaccmm': int(item.find("setaccmm").text.strip()),
'setaccmmdd': item.find("setaccmmdd").text.strip(),
'shotnisin': item.find("shotnisin").text.strip()
}
item_list.append(item_dict)
df = pd.DataFrame(item_list)
In [3]: print(df[['korsecnnm', 'divratecpri', 'divamtperstk', 'caltotmarttpcd']])
Out[3]:
korsecnnm divratecpri divamtperstk caltotmarttpcd
0 동남합성 29.50 9900.00 유가증권시장
1 서울도시가스 21.14 16750.00 유가증권시장
2 에스앤케이 KDR 19.80 3244.52 코스닥시장
3 대동전자 16.20 500.00 유가증권시장
4 바다로19호선박투자회사 12.80 0.00 유가증권시장
5 리드코프 11.88 800.00 코스닥시장
6 대신증권1우 10.90 1250.00 유가증권시장
7 대신증권 8.60 1200.00 유가증권시장
8 메리츠금융지주 8.60 900.00 유가증권시장
9 유수홀딩스 8.60 500.00 유가증권시장
KSD 증권정보포털 SEIBro에서 확인할 수 있는 정보와 동일한 것을 알 수 있다
바다로19호선박투자회사의 경우 배당금이 아니라 '분배금'으로 매달 배당금 형식으로 선박 투자에 대한 용선료를 주주들에게 지급하는데, 배당금으로 집계되지 않아 0원으로 표기되어 있다 (그런데 시가배당률은 또 집계가 되어있다...)
또한, 에스앤케이 KDR과 같이 주식예탁증서(Depositary Receipt)에 대해서도 종목명에 명확히 기재되어 있으니 확인이 필요하다 (보통 국내시장에서 KDR은 유상증자에 대한 내용인데, SNK같은 해외법인이 국내시장에 상장할 때 사용하는 방식 중 하나, 워낙 고배당이었기에 논란이 일어서 주식하는 사람 대부분이 한번쯤은 들어봤을 듯?)
또한, 분기배당하는 기업의 경우 1년간 배당 총액을 합산하여 주당배당금과 시가배당률을 산정하니 참고해야 한다 (대부분 기업은 연말 1회 배당이긴 하지만 ㅎㅎ)
다음과 같이 함수로 만들어보자 (데이터프레임 칼럼명도 보기쉽게 한글로 바꿔주자)
import requests
from bs4 import BeautifulSoup
import pandas as pd
def getDevidendRank(year: int, count: int = 100, market: int = None) -> pd.DataFrame:
"""
market: 상장구분 (11=유가증권, 12=코스닥, 13=K-OTC, 14=코넥스, 50=기타비상장)
"""
url_base = "http://api.seibro.or.kr/openapi/service/StockSvc"
url_spec = "getDividendRankN1"
url = url_base + "/" + url_spec
api_key_utf8 = "Your key from data.go.kr"
api_key_decode = requests.utils.unquote(api_key_utf8, encoding='utf-8')
params = {
"serviceKey": api_key_decode,
"rankTpcd": 1, # 1 = 시가배당률, 2 = 액면가배당률
"year": year,
"numOfRows": count,
"pageNo": 1,
}
if market is not None:
params['listTpcd'] = market
response = requests.get(url, params=params)
xml = BeautifulSoup(response.text, "lxml")
items = xml.find("items")
item_list = []
for item in items:
item_dict = {
'caltotmarttpcd': item.find("caltotmarttpcd").text.strip(),
'divamtperstk': float(item.find("divamtperstk").text.strip()),
'divratecpri': float(item.find("divratecpri").text.strip()),
'divratepval': float(item.find("divratepval").text.strip()),
'issucocustno': item.find("issucocustno").text.strip(),
'korsecnnm': item.find("korsecnnm").text.strip(),
'num': int(item.find("num").text.strip()),
'pval': int(item.find("pval").text.strip()),
'secnkacd': item.find("secnkacd").text.strip(),
'setaccmm': int(item.find("setaccmm").text.strip()),
'setaccmmdd': item.find("setaccmmdd").text.strip(),
'shotnisin': item.find("shotnisin").text.strip()
}
item_list.append(item_dict)
df = pd.DataFrame(item_list)
df.columns = ['시장구분', '주당배당금', '시가배당률', '액면가배당률', '발행회사번호', '종목명', '순위', '액면가', '주식종류', '결산월', '결산월일', '종목코드']
df = df[['순위', '종목코드', '종목명', '주식종류', '시장구분', '주당배당금', '시가배당률', '액면가배당률', '액면가', '결산월', '결산월일', '발행회사번호']]
return df
위와 같이 함수로 작성해서 시장별로 구분된 순위를 따로 쿼리할 수 있다
In [4]: df1 = getDevidendRank(2020, 10, 11)
In [5]: df1
Out[5]:
순위 종목코드 종목명 주식종류 시장구분 ... 액면가배당률 액면가 결산월 결산월일 발행회사번호
0 1 023450 동남합성 보통주 유가증권시장 ... 1980.000000 500 12 1231 2345
1 2 017390 서울도시가스 보통주 유가증권시장 ... 335.000000 5000 12 1231 1739
2 3 008110 대동전자 보통주 유가증권시장 ... 100.000000 500 3 0331 811
3 4 155900 바다로19호선박투자회사 보통주 유가증권시장 ... 7.038356 5000 12 1231 18894
4 5 003545 대신증권1우 우선주 유가증권시장 ... 25.000000 5000 12 1231 354
5 6 003540 대신증권 보통주 유가증권시장 ... 24.000000 5000 12 1231 354
6 7 138040 메리츠금융지주 보통주 유가증권시장 ... 180.000000 500 12 1231 16786
7 8 000700 유수홀딩스 보통주 유가증권시장 ... 20.000000 2500 12 1231 70
8 9 153360 하이골드오션3호선박투자회사 보통주 유가증권시장 ... 2.358387 5000 12 1231 18460
9 10 001755 한양증권1우 우선주 유가증권시장 ... 16.000000 5000 12 1231 175
[10 rows x 12 columns]
In [6]: df2 = getDevidendRank(2020, 10, 12)
In [7]: df2
Out[7]:
순위 종목코드 종목명 주식종류 시장구분 ... 액면가배당률 액면가 결산월 결산월일 발행회사번호
0 1 950180 에스앤케이 KDR 보통주 코스닥시장 ... 0.0 0 7 0731 34462
1 2 012700 리드코프 보통주 코스닥시장 ... 160.0 500 12 1231 1270
2 3 078020 이베스트투자증권 보통주 코스닥시장 ... 11.0 5000 12 1231 4481
3 4 040420 정상제이엘에스 보통주 코스닥시장 ... 86.0 500 12 1231 6393
4 5 085910 네오티스 보통주 코스닥시장 ... 50.0 500 12 1231 11365
5 6 007330 푸른상호저축은행 보통주 코스닥시장 ... 55.0 1000 12 1231 733
6 7 190650 코리아에셋투자증권 보통주 코스닥시장 ... 6.0 5000 3 0331 6332
7 8 225190 삼양옵틱스 보통주 코스닥시장 ... 120.0 500 12 1231 25874
8 9 031330 에스에이엠티 보통주 코스닥시장 ... 30.0 500 12 1231 3133
9 10 029960 코엔텍 보통주 코스닥시장 ... 102.0 500 12 1231 2996
[10 rows x 12 columns]
2021년 자료의 경우 아직 공시자료(배당을 위한 주주명부폐쇠 등)들을 다 정리하지 못했는지, KSD를 통해서는 의미있는 자료를 얻기 힘들다
In [8]: df3 = getDevidendRank(2021, 50)
In [8]: df3[['순위', '종목명', '주당배당금', '시가배당률']]
Out[8]:
순위 종목명 주당배당금 시가배당률
0 1 바다로19호선박투자회사 0.000000 12.60
1 2 신영증권1우 4050.000000 6.98
2 3 신영증권 4000.000000 6.88
3 4 동남합성 4300.000000 6.20
4 5 이지스밸류플러스위탁관리부동산투자회사 303.000000 5.80
5 6 신한알파위탁관리부동산투자회사1우 825.000000 5.46
6 7 코리아에셋투자증권 450.000000 5.15
7 8 신한알파위탁관리부동산투자회사 341.000000 4.36
8 9 쌍용씨앤이 330.000000 4.10
9 10 대덕 300.000000 3.80
10 11 하이골드오션3호선박투자회사 0.000000 3.80
11 12 아이마켓코리아 450.000000 3.80
12 13 포스코 12000.000000 3.70
13 14 제이알글로벌위탁관리부동산투자회사 190.000000 3.60
14 15 마크로밀엠브레인 280.000000 3.20
15 16 미래에셋맵스제1호위탁관리부동산투자회사 153.000000 3.05
16 17 청담러닝 1000.000000 2.90
17 18 파트론 350.000000 2.89
18 19 이리츠코크렙기업구조조정부동산투자회사 0.000000 2.80
19 20 삼양옵틱스 300.000000 2.80
20 21 코람코에너지플러스위탁관리부동산투자회사 166.000000 2.80
21 22 리드코프 300.000000 2.80
22 23 엔에이치프라임위탁관리부동산투자회사 125.000000 2.70
23 24 기신정기 150.000000 2.70
24 25 대덕1우 305.000000 2.70
25 26 씨엠에스에듀 200.000000 2.70
26 27 현대중공업지주 1850.000000 2.58
27 28 이지스레지던스위탁관리부동산투자회사 130.000000 2.50
28 29 미원상사 5500.000000 2.44
29 30 디티알오토모티브 1000.000000 2.40
30 31 씨앤투스성진 500.000000 2.36
31 32 금비 1600.000000 2.33
32 33 롯데위탁관리부동산투자회사 139.759519 2.30
33 34 효성ITX 450.000000 2.20
34 35 풍강 100.000000 2.10
35 36 대덕전자 1우 305.000000 2.10
36 37 상신브레이크 80.000000 2.10
37 38 SBI 핀테크솔루션즈 174.821200 2.00
38 39 이에스알켄달스퀘어위탁관리부동산투자회사 0.000000 2.00
39 40 이씨에스텔레콤 130.000000 1.87
40 41 방림 45.000000 1.70
41 42 에스앤티에너지 400.000000 1.70
42 43 케이씨씨글라스 1000.000000 1.60
43 44 한온시스템 270.000000 1.60
44 45 S-OIL1우 1000.000000 1.60
45 46 SK텔레콤 5000.000000 1.57
46 47 디앤디플랫폼위탁관리부동산투자회사 81.000000 1.53
47 48 진양홀딩스 50.000000 1.50
48 49 하나금융지주 700.000000 1.50
49 50 고려신용정보 150.000000 1.50
2위와 3위에 나란히 랭크되어 있는 '신영증권1우' 및 '신영증권'의 21년도 반기보고서 공시자료를 보면
우선주 주당 4,050원 - 시가배당률 6.98%
보통주 주당 4,000원 - 시가배당률 6.88%
로 공시가 되어 있는 것을 알 수 있다
이와 같이 주주총회를 통해 배당에 대한 의결이 이미 결정된 경우 OpenAPI를 통해서도 쉽게 확인할 수 있지만 아직 주주총회를 하지 않은 종목들은 집계되지 않은 것을 알 수 있다 (즉, 당장의 투자에 활용하기는 힘들다... ㅠㅠ)
4. 정리
공공데이터포털의 주식정보서비스 API는 KSD SEIBro OpenAPI 중 일부를 소개해주는 것에 불과하기 때문에 관심있는 사람은 아래 SEIBro 오픈플랫폼 사이트에서 직접 가입할 경우 훨씬 더 많은 정보를 얻을 수 있다
https://openplatform.seibro.or.kr/websquare/startup_control.jsp?w2xPath=/startup/index.xml
참고로 위에서 구현한 코드의 requests - get 결과물의 url을 찍어보면 다음과 같이 api.seibro.or.kr이 도메인이 찍히는 것을 확인할 수 있다
In [9]: response.url
Out[9]: 'http://api.seibro.or.kr/openapi/service/StockSvc/getDividendRankN1?serviceKey=SV5xOdOCXxDs5yZxOsanMwoY9Jeht7UPM%2BnKqBY3tFIpAivokjm4XMm7Dr9QvXMgWXdwkxIeFRDHpgQaSQtmig%3D%3D&rankTpcd=1&year=2021&numOfRows=10&pageNo=1'
별도로 사이트를 가입하지 않고, 공공데이터포털에서 통합으로 서비스를 관리하고자 할 경우 유용하게 사용할 수 있는 API이지만, 운영계정으로 변경하지 않을 경우 기능별로 일일 트래픽이 100회로 제한되기 때문에 사용성이 떨어질 수 있으니 유의해야 한다
본 포스팅에서는 내가 관심있게 지켜보는 배당에 관한 항목만 살펴보았는데, 배당뿐만 아니라 다양한 정보를 쿼리할 수 있으니 직접 구현해보기 바란다
마지막으로 유가증권시장의 전체 종목의 단축코드(6자리)를 얻는 예제 코드를 작성해봤다 (시장별 단축코드 전체 조회, url 상세 = getShotnByMartN1)
def getStockCode(market: int = 11) -> pd.DataFrame:
"""
market: 상장구분 (11=유가증권, 12=코스닥, 13=K-OTC, 14=코넥스, 50=기타비상장)
"""
url_base = "http://api.seibro.or.kr/openapi/service/StockSvc"
url_spec = "getShotnByMartN1"
url = url_base + "/" + url_spec
api_key_utf8 = "Your key from data.go.kr"
api_key_decode = requests.utils.unquote(api_key_utf8, encoding='utf-8')
params = {
"serviceKey": api_key_decode,
"pageNo": 1,
"numOfRows": 100000,
"martTpcd": market
}
response = requests.get(url, params=params)
xml = BeautifulSoup(response.text, "lxml")
items = xml.find("items")
item_list = []
for item in items:
item_dict = {
'korsecnnm': item.find("korsecnnm").text.strip(),
'shotnisin': item.find("shotnisin").text.strip()
}
item_list.append(item_dict)
df = pd.DataFrame(item_list)
df.columns = ['종목명', '단축코드']
return df
(넉넉하게 1페이지에 최대 10만개 종목을 모두 불러오도록 구현)
In [10]: df1 = getStockCode(11)
In [11]: df1.head(5)
Out[11]:
종목명 단축코드
0 동화약품 000020
1 케이알모터스 000040
2 경방 000050
3 메리츠화재해상보험 000060
4 삼양홀딩스 000070
In [12]: df1.tail(5)
Out[12]:
종목명 단축코드
938 에스케이위탁관리부동산투자회사 395400
939 엔에이치올원위탁관리부동산투자회사 400760
940 케이카 381970
941 미래에셋글로벌위탁관리부동산투자회사 396690
942 신한서부티엔디위탁관리부동산투자회사 404990
In [13]: len(df1)
Out[13]: 943
In [14]: df2 = getStockCode(12)
In [15]: df2.head(5)
Out[15]:
종목명 단축코드
0 이스트아시아홀딩스인베스트먼트리미티드 900110
1 삼천당제약 000250
2 중앙에너비스 000440
3 신라섬유 001000
4 안국약품 001540
In [16]: df2.tail(5)
Out[16]:
종목명 단축코드
1529 유진기업인수목적7호 388800
1530 대신밸런스제11호기업인수목적 397500
1531 교보11호기업인수목적 397880
1532 해성산업1우 03481K
1533 하이제7호기업인수목적 400840
In [17]: len(df2)
Out[87]: 1534
유가증권시장(코스피) 및 코스닥 시장에에 상장된 종목은 2021년 12월 21일 기준 각각 943개, 1534개인 것을 확인할 수 있다
증권사 프로그램이나 앱, 포털사이트 등을 이용하면 종목 개별 종목코드정도는 쉽게 얻을 수 있지만 이렇게 전체 상장종목들에 대해서 단축코드를 개인 DB등에 저장해놓고 필요할 때마다 쿼리해서 활용하면 훨씬 스마트한 투자(?)를 할 수 있다
끝~!
'Data Analysis > Data Engineering' 카테고리의 다른 글
웹크롤링 - DART 기업개황 업종별 기업 리스트 가져오기 (2) (0) | 2022.01.07 |
---|---|
웹크롤링 - DART 기업개황 업종별 기업 리스트 가져오기 (1) (0) | 2022.01.06 |
웹크롤링 - 금융감독원 전자공시시스템(DART) 특정일자 공시문서 전체 리스트 크롤링 (4) | 2021.10.01 |
금융감독원::DART 공시문서 js 렌더링된 HTML 가져오기 (4) | 2021.09.24 |
금융감독원::OPENDART 전자공시 Open API 사용하기 (17) | 2021.09.18 |