지난 포스팅들을 통해 전자공시시스템(DART)의 API를 이용하여 데이터를 받는 방법, R과 텔레그램을 연결하는 방법, 그리고 스케쥴러를 이용하여 자동으로 정보를 제공하는 방법에 대해 알아보았습니다.
- R에서 전자공시시스템(DART) API를 이용한 크롤링
- R을 이용한 텔레그램봇 만들기 (시장 레포트 텔레그램으로 전송하기)
- R을 이용한 텔레그램봇 만들기 (스케쥴러를 사용하여 자동 정보 전송)
이번 시간에는 위의 기능들을 활용하여, 관심종목들의 공시정보를 실시간으로 텔레그램에 전송하는 방법에 대해 배워보도록 하겠습니다.
# 텔레그램 연결 library(telegram.bot) bot = Bot(token = "Your Telegram API Key") updates = bot$getUpdates() chat_id = updates[[1]]$message$chat$id # dart api 연결 library(jsonlite) library(readr)
먼저 텔레그램봇의 채팅방 ID를 불러오도록 합니다. chat_id에 제대로 값을 불러오지 못할 경우, 해당 채팅방에서 아무 텍스트나 입력한 후 다시 코드를 실행시키면 제대로 값이 불러와집니다. 그 후 공시정보를 받아오기 위한 jsonlite 패키지와 csv 파일을 읽기위한 readr 패키지를 불러옵니다.
그 후에는 1. 관심종목 리스트, 2. 전송된 공시 리스트 파일을 만들어야 합니다.
먼저 관심종목은 KRX300 지수의 구성종목들을 예시로 하며, 현재 전송된 공시가 없으므로 빈 파일이 됩니다. 해당 파일을 각각 'krx_300.csv'와 'rcp_list.csv' 이름으로 저장합니다.
# Default # guess_encoding('C:/Users/Henry/Dropbox/R/telegram_bot/krx_300.csv') my.universe = read_csv('C:/Users/Henry/Dropbox/R/telegram_bot/krx_300.csv', locale = locale(encoding = 'EUC-KR'), col_names = FALSE) my.universe = unlist(my.universe) rcp_list = read_csv('C:/Users/Henry/Dropbox/R/telegram_bot/rcp_list.csv', locale = locale(encoding = 'EUC-KR'), col_names = FALSE) rcp_list = unlist(rcp_list)
먼저 readr 패키지의 guess_encoding() 함수를 이용하여 저장한 파일의 인코딩 정보를 확인합니다. 대부분의 경우 UTF-8 이거나 EUC-KR 형태로 저장되어 있습니다. read_csv() 함수를 이용하여 csv 파일을 불러오며 관심종목은 my.universe에, 전송 리스트는 rcp_list에 저장하도록 합니다. 또한 unlist() 함수를 이용하여 벡터 형태로 변경해 주도록 합니다.
이번에는 공시 정보를 받을 API 주소를 만들도록 합니다. 당일 공시 최근 100건의 API 주소는 다음과 같습니다.
http://dart.fss.or.kr/api/search.json?auth=YOUR_DART_API_KEY&page_set=100
해당 url을 웹페이지에 직접 입력하면 다음과 같이 JSON 형태로 데이터를 보여줍니다.
이제 위의 url 주소를 코드 내에서 만들어 주어야 합니다.
api.key = 'YOUR_DART_API_KEY' url = paste0('http://dart.fss.or.kr/api/search.json?auth=', api.key,'&주요사항보고서&page_set=100') url [1] "http://dart.fss.or.kr/api/search.json?auth=YOUR_DART_API_KEY&주요사항보고서&page_set=100"
원래 대로라면 위의 코드를 이용하여 금일 공시에 해당하는 url 정보를 만들 수 있습니다. 그러나 문제는 '주요사항보고서'라는 한글에 있습니다. 코드 내에 한글이 있을 경우 나중에 스케쥴러를 통한 코드가 돌아가는데 에러가 발생하므로, 해당 글자를 UTF-16에 해당하는 문자(\uc8fc\uc694\uc0ac\ud56d\ubcf4\uace0\uc11c)로 바꿔주도록 하겠습니다. 이를 적용한 코드는 다음과 같습니다. 인코딩 컨버팅은 [Link]에서 확인하실 수 있습니다.
api.key = 'YOUR_DART_API_KEY' url = paste0('http://dart.fss.or.kr/api/search.json?auth=', api.key,'&','\uc8fc\uc694\uc0ac\ud56d\ubcf4\uace0\uc11c','&page_set=100') url [1] "http://dart.fss.or.kr/api/search.json?auth=YOUR_DART_API_KEY&주요사항보고서&page_set=100
UTF-16 형태로 입력하여도 출력되는 형태는 기존 한글과 동일합니다. 이제 위에서 만든 주소를 이용하여 공시 데이터를 다운로드 받도록 하겠습니다.
data = fromJSON(url) data.df = data$list head(data.df, 3) crp_cls crp_nm crp_cd rpt_nm 1 K 유틸렉스 263050 임원ㆍ주요주주특정증권등소유상황보고서 2 E 리젠시빌주택 01026412 임원의변동 3 K 화진 134780 [기재정정]참고서류 rcp_no flr_nm rcp_dt rmk 1 20190318000297 DE LA CALLE AGUSTIN 20190318 2 20190318000296 리젠시빌주택 20190318 공 3 20190318000295 황해용 20190318
crp_nm은 종목 이름, crp_cd는 종목 티커, rpt_nm은 공시 제목, rcp_no는 공시 번호를 나타냅니다. 이중 rcp_no를 이용하여 해당 공시의 url을 생성할 수 있습니다.
회사별검색을 해보면 가장 상단에 조회되는 내용이 우리가 찾고자 하는 공시입니다.
해당 공시를 클릭하여 url 정보를 확인해보면, 위의 rcpNo= 글자 뒤의 문서번호가 우리가 다운로드 받은 JSON 형식의 데이터에서 rcp_no 컬럼의 데이터와 동일함을 알수 있습니다. 이를 이용하면 모든 공시들의 url 정보를 생성할 수 있습니다.
data.df$name = paste(data.df$crp_nm, data.df$rpt_nm) data.df$url = paste0('http://dart.fss.or.kr/dsaf001/main.do?rcpNo=', data.df$rcp_no)
data.new = data.df data.new = data.new[data.new$crp_nm %in% my.universe, ] data.new = data.new[!data.new$rcp_no %in% rcp_list, ] send.message = paste(data.new$name, data.new$url, sep = '\n') sapply(send.message, function(x) {bot$sendMessage(chat_id = chat_id, x)})
공시데이터 중 1) 관심 종목에 해당하는 종목, 2) 이미 전송하지 않은 공시에 해당하는 부분만을 추출하도록 합니다. 먼저 crp_nm 즉 종목명이 my.universe에 존재하는 행만을 선택합니다. 그 후 rcp_no 즉 공시번호가 rcp_list에 존재하지 않는, 즉 이전에 전송되지 않은 행만을 선택하도록 합니다. 그 후 name, url 정보를 합쳐 send.message 변수에 저장하며, bot$sendMessage() 함수를 통해 텔레그램에 전송하도록 합니다.
금일 공시 내역 중 관심종목에 해당하는 종목, 그리고 전송되지 않은 공시 내용의 제목과 url이 전송되는 것이 확인됩니다. 해당 url을 클릭하면 각 공시 내용의 웹페이지로 이동하게 됩니다.
# 리스트에 저장 rcp_list = c(rcp_list, data.new$rcp_no) write_csv(data.frame(rcp_list), path ='C:/Users/Henry/Dropbox/R/telegram_bot/rcp_list.csv', col_names = FALSE)
공시를 중복으로 전송하는 일을 막기위해, 전송된 공시 리스트를 새로 업데이트 하도록 합니다. 기존 rcp_list와 새로운 rcp_no를 합친 후, 'rcp_list.csv' 파일에 새롭게 저장하도록 합니다.
rcp_list.csv 파일을 확인해보면, 방금 전송된 공시들의 문서번호가 저장되어 있습니다. 이렇게 조건에 해당하는 공시가 발송될때마다 해당 파일에 전송된 내역들이 쌓이게 됩니다. 위의 코드들을 연결하면 아래와 같으며, 해당 코드를 'dart_to_telegram.R'로 저장하도록 합니다.
# 텔레그램 연결 library(telegram.bot) bot = Bot(token = "Your Telegram API Key") updates = bot$getUpdates() chat_id = updates[[1]]$message$chat$id # dart api 연결 library(jsonlite) library(readr) # Default # guess_encoding('C:/Users/Henry/Dropbox/R/telegram_bot/krx_300.csv') my.universe = read_csv('C:/Users/Henry/Dropbox/R/telegram_bot/krx_300.csv', locale = locale(encoding = 'EUC-KR'), col_names = FALSE) my.universe = unlist(my.universe) rcp_list = read_csv('C:/Users/Henry/Dropbox/R/telegram_bot/rcp_list.csv', locale = locale(encoding = 'EUC-KR'), col_names = FALSE) rcp_list = unlist(rcp_list) api.key = 'YOUR_DART_API_KEY' url = paste0('http://dart.fss.or.kr/api/search.json?auth=', api.key,'&','\uc8fc\uc694\uc0ac\ud56d\ubcf4\uace0\uc11c','&page_set=100') # 주요사항보고서 최근 100 종목 다운로드 data = fromJSON(url) data.df = data$list data.df$name = paste(data.df$crp_nm, data.df$rpt_nm) data.df$url = paste0('http://dart.fss.or.kr/dsaf001/main.do?rcpNo=', data.df$rcp_no) # 선택한 유니버스 공시만 원하는 경우 data.new = data.df data.new = data.new[data.new$crp_nm %in% my.universe, ] data.new = data.new[!data.new$rcp_no %in% rcp_list, ] send.message = paste(data.new$name, data.new$url, sep = '\n') sapply(send.message, function(x) {bot$sendMessage(chat_id = chat_id, x)}) # 리스트에 저장 rcp_list = c(rcp_list, data.new$rcp_no) write_csv(data.frame(rcp_list), path ='C:/Users/Henry/Dropbox/R/telegram_bot/rcp_list.csv', col_names = FALSE)
이제 해당 파일을 이용하여 1분마다 공시내역을 전송하는 스케쥴러를 만들도록 하겠습니다. DART는 하루에 10,000번의 API 접근을 허용하며, 1분마다 API에 접근할 경우 총 60 * 24 = 1440번 API에 접근하므로 무리가 없습니다.
library(taskscheduleR) tele_auto = file.path("C:/Users/Henry/Dropbox/R/telegram_bot/dart_to_telegram.R") taskscheduler_create(taskname = "dart_api_bot", rscript = tele_auto, schedule = "MINUTE", starttime = format(Sys.time() + 61, "%H:%M"), startdate = format(Sys.time(), "%Y/%m/%d"), modifier = 1)
앞서 저장한 dart_to_telegram.R 코드를 실행하는 스케쥴러를 dart_api_bot 이라는 이름으로 저장하여, 매 1분마다 코드를 실행하게 됩니다. 즉 1분마다 최근 공시 100개를 다운로드 받고, 관심종목 중 아직 전송되지 않은 공시 내역을 자동으로 텔레그램에 전송하게 됩니다.
관심종목들의 공시가 있을때 마다 텔레그램을 통해 내역이 전송되는 것이 확인됩니다. 공시의 많은 분량이 증권사의 ELS/DLS와 같은 증권발행보고서 이므로, 공시 제목에 '증권실적발행실적보고서'가 있는 경우는 제외한다면 더욱 중요한 공시만 받아볼 수 있습니다.
댓글 없음:
댓글 쓰기