데이터 기반 기업 가치를 평가해보는 연습을 해보았습니다.
# 팩터의 자동변환을 방지하는 함수
options(stringsAsFactors = FALSE)
# 패키지를 설치하고 실행하는 함수
pkgload <- function(x){
for(i in x){
while(require(i, character.only = TRUE)==FALSE){
install.packages(i)
}
}
}
x <- c("KoNLP", "dplyr", "rvest", "httr", "stringr", "googleVis", "RColorBrewer",
"knitr", "xlsx", "PortfolioAnalytics", "jsonlite", "wordcloud", "RSelenium",
"lubridate", "xts", "quantmod", "PerformanceAnalytics", "ggplot2", "gridExtra",
"EnvStats", "tseries", "XML")
# 패키지 실행
pkgload(x)
# 주가 최근 값을 가져오는 함수
stockcrawl_last <- function(code, name){ # code <- "068270"; name <- "셀트리온"
url_base <- paste0("http://finance.naver.com/item/sise_day.nhn?code=", code, "&page=1")
contents <- GET(url_base)
all.price <- read_html(contents) %>% html_nodes('table') %>% .[1] %>% html_table()
all.price <- data.frame(all.price) %>% filter(!(날짜==""))
all.price <- all.price %>% mutate(날짜 = as.Date(날짜, format="%Y.%m.%d"))
for(i in 2:ncol(all.price)){
all.price[,i] <- as.numeric(gsub(",","",all.price[,i]))
}
all.price <- data.frame(종목코드 = code, 기업명 = name, all.price[,c("날짜", "종가", "전일비", "거래량")])
return(all.price[1,])
}
# 주가 전체를 가져오는 함수
stockcrawl <- function(code, name, number=0){ # code <- "068270"; name <- "셀트리온" ; number <- 10
url_base <- paste0("http://finance.naver.com/item/sise_day.nhn?code=", code, "&page=", 1)
contents <- GET(url_base)
# 마지막 페이지를 가져오기
pg.last <- strsplit(read_html(contents) %>%
html_nodes("td.pgRR a") %>% html_attr("href"), "&")[[1]][2]
pg.last <- strsplit(pg.last, "=")[[1]][2]
# 0인 경우는 마지막 페이지 그렇지 않은 경우는 개수만큼 가져오기
if(number == 0){
pg.last <- pg.last
}else pg.last <- as.integer(number/10)
tot.price <- data.frame()
for (page in 1:pg.last){ # page <- 1
print(page)
url_base <- paste0("http://finance.naver.com/item/sise_day.nhn?code=", code, "&page=", page)
contents <- GET(url_base)
content(contents)
all.price <- read_html(contents) %>% html_nodes('table') %>% .[1] %>% html_table()
all.price <- data.frame(all.price) %>% filter(!(날짜==""))
all.price <- all.price %>% mutate(날짜 = as.Date(날짜, format="%Y.%m.%d"))
for(i in 2:ncol(all.price)){
all.price[,i] <- as.numeric(gsub(",","",all.price[,i]))
}
all.price <- data.frame(종목코드 = code, 기업명 = name, all.price[,c("날짜", "종가", "전일비", "거래량")])
tot.price <- rbind(tot.price, all.price)
}
tot.price <- tot.price %>% arrange(날짜)
tseries <- xts(tot.price[,"종가"], order.by=tot.price[,"날짜"])
colnames(tseries) <- "종가"
return(tseries)
}
# 수정 주가 전체를 가져오는 함수
stockcrawl_adj_new <- function(code, name, number=0){ # code <- "033270" ; name <- "유나이티드"
url <- paste0("https://fchart.stock.naver.com/sise.nhn?symbol=",code,"&timeframe=day&count=1000&requestType=0")
contents <- GET(url)
data <- read_html(iconv(contents,from = "ISO-8859-1", to = "UTF-8"), encoding = "utf8") %>%
html_nodes("item") %>% html_attr("data")
data1 <- data %>% strsplit('\\|')
data2 <- lapply(data1, function(x) {x[c(1, 5, 6)] %>% t() %>% data.frame()})
data3 <- do.call(rbind, data2)
data3[,2] <- as.numeric(data3[,2])
data3[,3] <- as.numeric(data3[,3])
rownames(data3) <- ymd(data3[,1]) %>% as.character
data3[,1] <- NULL
# 0인 경우는 마지막까지 그렇지 않은 경우는 개수만큼 가져오기
if(number == 0){
data4 <- data3
}else{
data4 <- data3[(nrow(data3)-number):nrow(data3),]
}
data5 <- as.xts(data4)
colnames(data5) <- c("수정주가", "거래량")
data5$return <- Delt(data5[,1])
colnames(data5) <- c("수정주가", "거래량", "수익률")
return(data5)
}
# 포트를 여는 함수
port.open <- function(){
portn <<- as.integer(runif(1, 1,5000))
rD <<- rsDriver(port=portn, browser="chrome", chromever = "75.0.3770.142")
remDr <<- rD[["client"]]
}
# 포트를 닫는 함수
port.close <- function(){
remDr$close()
rD[["server"]]$stop()
}
# 업종키워드에 해당하는 업종에 속하는 기업리스트를 가져오는 함수
stock_code_list <-function(ind_key){
remDr$navigate("http://marketdata.krx.co.kr/mdi#document=040601")
webElem <- remDr$findElement("css", "div.design-center span.button-mdi-group button")
remDr$executeScript("$.down(this,'xls','formc81e728d9d4c2f636f067f89cc14862c')",
args = list(webElem))
Sys.sleep(20) # 데이터 저장 시간 고려
stock_list0 <- readxl::read_excel("C:/Users/user/Downloads/data.xls", sheet = 1)
stock_list <- data.frame()
# "전체"일 경우는 모든 코드, 업종이 선택된 경우는 업종만 가져오기
for ( i in ind_key ){
if( i == "전체"){
stock_list <- stock_list0
break
}else{
temp <- stock_list0 %>% filter(grepl(i, 업종) == TRUE )
stock_list <- rbind( stock_list, temp)
}
}
stock_list <- unique(stock_list)
return(stock_list)
}
# 재무추정결과를 가져오는 함수 - 제한된 기업만 존재함
get_fin <- function(code){ # code <- "068270"; name <- "셀트리온"
url <- paste0("https://navercomp.wisereport.co.kr/v2/company/c1010001.aspx?cmp_cd=",code)
remDr$navigate(url)
# url 가져오기
data <- GET(url)
# html 파일 읽고 텍스파일 가져오기
data.text <- read_html(data) %>% html_text()
# 연간실적 테이블의 encparam과 id 번호를 가져오기
data.param <- str_match(data.text, "encparam: '(.*)'")[2]
data.id <- str_match(data.text, "id: '([a-zA-Z0-9]*)' ?")[2]
# 새로운 url 생성 및 url 가져오기
url_fs <- paste0('https://navercomp.wisereport.co.kr/v2/company/ajax/cF1001.aspx?cmp_cd=', code, '&fin_typ=0&freq_typ=Y&encparam=',
data.param,"&id=",data.id)
remDr$executeScript(paste0("window.open('",url_fs,"')"))
data_fs <- GET(url_fs)
# /html/body/table[2] 로 시작되는 node의 내용을 가져오기
data_table <- read_html(data_fs) %>%
html_node(xpath = '/html/body/table[2]') %>%
html_table(fill = TRUE)
# 열이름 생성
colnames(data_table) <- data_table[1, ]
# 첫줄 제거
data_table <- data_table[-1, ]
# 행의 이름은 NULL로 처리
rownames(data_table) <- NULL
# 첫번째 컬럼을 행이름으로 정의
data_table <- tibble::column_to_rownames(data_table, var = '주요재무정보')
# 문자를 숫자로 바꾸기 위해 ","를 제거하고 숫자로 변환
for (j in 1:ncol(data_table)) {
data_table[, j] = str_replace_all(data_table[, j], ',', '') %>% as.numeric()
}
# 컬럼의 이름에서 특수문자 제거
# \r\n\t\t\t\t\t\t\t\t\t 를 나타내는 [\r\n\t+] 를 활용
colnames(data_table) <- str_replace_all(colnames(data_table), "[\r\n\t+]" , "")
# 생성된 테이블 리턴
return(data_table)
}
# 포괄손익계산서를 가져오는 함수
get_fin_is <- function(code){ # code <- "005930"
url <- paste0("https://navercomp.wisereport.co.kr/v2/company/c1030001.aspx?cmp_cd=",code)
remDr$navigate(url)
# url 가져오기
data <- GET(url)
# html 파일 읽고 텍스파일 가져오기
data.text <- read_html(data) %>% html_text()
# 연간실적 테이블의 encparam과 id 번호를 가져오기
data.param <- str_match(data.text, "encparam: '(.*)'")[2]
# 연간 재무제표 URL 생성하고 NEW TAB에서 보여주기
# 새로운 url 생성 및 url 가져오기
url_is <- paste0("https://navercomp.wisereport.co.kr/v2/company/cF3002.aspx?cmp_cd=", code, "&frq=0&rpt=0&finGubun=MAIN&frqTyp=0&cn=&encparam=",
data.param)
remDr$executeScript(paste0("window.open('",url_is,"')"))
Sys.sleep(1)
data_is <- fromJSON(url_is)[["DATA"]]
data_is <- data_is[,c("ACKIND", "ACCODE", "ACC_NM", "DATA1", "DATA2", "DATA3", "DATA4", "DATA5")]
colnames(data_is) <- tolower(c("ACKIND", "ACCODE", "ACC_NM",
gsub("<br />" , "", fromJSON(url_is)[["YYMM"]][1:5])))
data_is$acc_nm <- gsub("[.*]","",data_is$acc_nm)
return(data_is)
}
# 재무상태표를 가져오는 함수
get_fin_fs <- function(code){ # code <- "005930"
url <- paste0("https://navercomp.wisereport.co.kr/v2/company/c1030001.aspx?cmp_cd=",code)
remDr$navigate(url)
# url 가져오기
data <- GET(url)
# html 파일 읽고 텍스파일 가져오기
data.text <- read_html(data) %>% html_text()
# 연간실적 테이블의 encparam과 id 번호를 가져오기
data.param <- str_match(data.text, "encparam: '(.*)'")[2]; data.param
# 새로운 url 생성 및 url 가져오기
# remDr$open()
url_fs <- paste0("https://navercomp.wisereport.co.kr/v2/company/cF3002.aspx?cmp_cd=", code, "&frq=0&rpt=1&finGubun=MAIN&frqTyp=0&cn=&encparam=",
data.param)
remDr$executeScript(paste0("window.open('",url_fs,"')"))
Sys.sleep(1)
data_fs <- fromJSON(url_fs)[["DATA"]]
data_fs <- data_fs[,c("ACKIND", "ACCODE", "ACC_NM", "DATA1", "DATA2", "DATA3", "DATA4", "DATA5")]
colnames(data_fs) <- tolower(c("ACKIND", "ACCODE", "ACC_NM",
gsub("<br />" , "", fromJSON(url_fs)[["YYMM"]][1:5])))
data_fs$acc_nm <- gsub("[.*]","",data_fs$acc_nm)
return(data_fs)
}
# 현금흐름표를 가져오는 함수
get_fin_cf <- function(code){ # code <- "005930"
url <- paste0("https://navercomp.wisereport.co.kr/v2/company/c1030001.aspx?cmp_cd=",code)
remDr$navigate(url)
# url 가져오기
data <- GET(url)
# html 파일 읽고 텍스파일 가져오기
data.text <- read_html(data) %>% html_text()
# 연간실적 테이블의 encparam과 id 번호를 가져오기
data.param <- str_match(data.text, "encparam: '(.*)'")[2]
# 새로운 url 생성 및 url 가져오기
url_cf <- paste0("https://navercomp.wisereport.co.kr/v2/company/cF3002.aspx?cmp_cd=", code, "&frq=0&rpt=2&finGubun=MAIN&frqTyp=0&cn=&encparam=",
data.param)
remDr$executeScript(paste0("window.open('",url_cf,"')"))
Sys.sleep(1)
data_cf <- fromJSON(url_cf)[["DATA"]]
data_cf <- data_cf[,c("ACKIND", "ACCODE", "ACC_NM", "DATA1", "DATA2", "DATA3", "DATA4", "DATA5")]
colnames(data_cf) <- tolower(c("ACKIND", "ACCODE", "ACC_NM",
gsub("<br />" , "", fromJSON(url_cf)[["YYMM"]][1:5])))
data_cf$acc_nm <- gsub("[.*]","",data_cf$acc_nm)
return(data_cf)
}
# 베타와 시가총액을 가져오는 함수
capital_beta <- function(code, name){ # code <- "176750"
url <- paste0("https://navercomp.wisereport.co.kr/v2/company/c1010001.aspx?cmp_cd=",code)
content <- GET(url)
summary.table <- read_html(content) %>%
html_nodes('table') %>%
.[2] %>%
html_table()
beta <- as.numeric(summary.table[[1]][6,2])
nstock <- as.numeric( gsub("[,주]","",unlist(strsplit(summary.table[[1]][7,2], "/"))[1]) )
# 시가총액 (단위:억원)
capital <- as.numeric(gsub("[,억원]","",summary.table[[1]][5,2]))
capital_result <- data.frame(
종목코드 = code, 업체명 = name,
베타 = beta, 발행주식수 = nstock, 시가총액 = capital)
return(capital_result )
}
# KOSPI RAW 데이터를 가져오는 함수
kospi.crawl <- function(number=0){ # number <- 100
url <- paste0("https://finance.naver.com/sise/sise_index_day.nhn?code=KOSPI&page=",1)
content <- GET(url)
# 마지막 페이지를 가져오기
pg.last <- strsplit(read_html(content) %>%
html_nodes("td.pgRR a") %>% html_attr("href"), "&")[[1]][2]
pg.last <- strsplit(pg.last, "=")[[1]][2]
# 0인 경우는 마지막 페이지 그렇지 않은 경우는 개수만큼 가져오기
if(number == 0){
pg.last <- as.numeric(pg.last)
}else pg.last <- ceiling(number/6)
kospi.data <- data.frame()
t <- 0
for(i in 1:pg.last){ # i <- 1
print(t)
url <- paste0("https://finance.naver.com/sise/sise_index_day.nhn?code=KOSPI&page=",i)
content <- GET(url)
# XPath 위치 확인하여 테이블 가져오기
data_table <- read_html(content) %>%
html_node(xpath = '/html/body/div/table[1]') %>%
html_table(fill = TRUE)
# 날짜 없는 것은 제거
data_table <- data_table[!(data_table[,"날짜"]=="") & !is.na(data_table[,"날짜"]), ]
# 행의 이름은 NULL로 처리
rownames(data_table) <- NULL
data_table[,"등락률"] <- as.numeric(gsub("[%+-]","",data_table[,"등락률"]))*0.01
# 문자를 숫자로 바꾸기 위해 ","를 제거하고 숫자로 변환
for (j in 2:ncol(data_table)) {
data_table[, j] = str_replace_all(data_table[, j], ',', '') %>% as.numeric()
}
kospi.data <- rbind(kospi.data, data_table)
t <- t + 1
if ( t %% 100 == 0 ) Sys.sleep(2)
}
kospi.data <- kospi.data[1:number,]
# 날짜타입으로 수정
kospi.data[,"날짜"] <- as.Date(kospi.data[,"날짜"], "%Y.%m.%d")
# xts로 변환
kospi.xts <- as.xts(kospi.data[,2], order.by=kospi.data[,1])
colnames(kospi.xts) <- "kospi"
# 연별자료 변환하고 이름 정하기 to.yearly(), to.monthly() 함수 활용
kospi.year <- to.yearly(kospi.xts)[,4]
colnames(kospi.year) <- "kospi"
# 연간수익률 평균 구하기, 연간수익률의 기대값 추정
returns.data <- CalculateReturns(kospi.year[-length(kospi.year)])
returns.data <- na.omit(returns.data)
# 평균 구해보기
market.return <- mean(returns.data, trim=0.1)
return(market.return)
}
# KOSPI 수익률과 무위험국채 수익률을 구하는 함수
macro_crawl <- function(){
message(sprintf("KOSPI수익률과 무위험국채수익률을 가져옵니다. \n"))
########################################################################################
# 시장포트폴리오(KOSPI) 체결가격 시작페이지와 끝 페이지 받아서 수익률 만들기
kospi.data <- kospi.crawl(1300)
market.return <- kospi.data
########################################################################################
# 무위험 국채 수익률 가져오기
sample <- "T1JKFDLBBNP41Q1S8NY0"
url <- "http://ecos.bok.or.kr/api/StatisticSearch/sample/json/kr/1/10/060Y001/DD/20190401/20190420/010210000/"
data_rf <- fromJSON(url)[[1]][[2]]
risk.free.rate <- as.numeric(data_rf[nrow(data_rf),"DATA_VALUE"])/100
data_macro <- data.frame(market.return=market.return, risk.free.rate=risk.free.rate)
}
# FCF에 근거한 주식가치평가 함수
fcf_value <- function(code, name, market.return, risk.free.rate){
# code <- "068270"; name <- "셀트리온"
# code <- "085660"; name <- "차바이오텍"
message("#################################################################\n",
"#################################################################\n",
sprintf("%s, %s의 분석을 시작합니다.\n", code, name))
########################################################################################
## 네이버 파이낸스 url에서 재무정보 가져오기
port.open() # 포트를 하나 열어서 크롬 드라이버 rD와 클라이언트 remDr 설정
message("#################################################################\n",
"#################################################################\n",
sprintf("재무추정정보를 가져옵니다.\n"))
data_table <- get_fin(code) # 재무추정정보
message(sprintf("포괄손익계산서 정보를 가져옵니다.\n"))
data_is <- get_fin_is(code) # 포괄손익계산서
message(sprintf("재무상태표 정보를 가져옵니다.\n"))
data_fs <- get_fin_fs(code) # 재무상태표
message(sprintf("현금흐름표 정보를 가져옵니다.\n"))
data_cf <- get_fin_cf(code) # 현금흐름표
data_table2 <- rbind(data_is, data_fs, data_cf)
port.close() # 클라이언트 remDr과 rD를 모두 닫음
message(sprintf("가중평균자본비용을 계산합니다. \n"))
########################################################################################
# 베타, 주식수 및 시가총액 가져오기
capital_result <- capital_beta(code, name)
beta <- capital_result[,"베타"]
capital <- capital_result[,"시가총액"]
########################################################################################
# CAPM을 활용하여 자본비용 계산
capital.cost <- risk.free.rate + beta*(market.return - risk.free.rate)
########################################################################################
# 타인자본비용 및 부채 가져오기
# 부채총액 가져오기 (단위: 억원)
# 부채의 경우에는 장부가나 시가가 거의 차이없다고 가정함
# 실제로 부도위험의 증가같은 이벤트가 없는 경우에는 채권의 시장가치와 장부가치는 거의 동등
# 총부채
debt <- data_table[rownames(data_table)=="부채총계",5]
# 이자비용 가져오기
# 이자비용 가져오기(단위: 억원)
int.cost <- as.numeric(data_is[data_is[,2]==202560,8])
# 이자부채 가져오기(단위: 억원) : 타인자본비용을 구하기 위해 시기 맞춤
adj_debt <- as.numeric(data_table[rownames(data_table)=="이자발생부채",5])
# 타인자본비용
debt.cost <- int.cost/(adj_debt)
########################################################################################
# 가중평균자본비용
wacc <- debt.cost*debt/(debt+capital) + capital.cost*capital/(debt+capital)
message(sprintf("주식가치를 계산합니다. \n"))
########################################################################################
# 기업가치
fcf <- data_table[row.names(data_table)=="FCF",6:8]
# fcf가 없는 경우에는 계산하여 추정: 평균성장률 계산
if (is.na(fcf[1])){
gr <- t(data_table[row.names(data_table)=="FCF",3:5])
gr <- mean(Delt(gr), na.rm=T)
fcf <- data_table[row.names(data_table)=="FCF",3:5]*(1+gr)
}
# 기업가치는 2단계 모형을 적용하시오.
# 여기서 2단계 모형은 미래 3개년 동안의 현재가치와 그 이후는 명목경제성장률로 성장한다고
# 가정하는 형태임
# 기업가치
corp.value <- fcf[1]/(1+wacc) + fcf[2]/(1+wacc)^2 + fcf[3]/(1+wacc)^3 + fcf[3]*(1+0.025)/(wacc - 0.025)*1/(1+wacc)^3
# 자기자본의 가치 = 기업가치 - 부채가치
capital.value <- as.numeric(corp.value) - debt
# 주식의 개수
nstock <- data_table[row.names(data_table)=="발행주식수(보통주)",5]
# 주식가치 (단위: 천원)
stock.value <- capital.value / nstock * 100000
# 주식가치출력
message(sprintf("%s, %s의 평가된 주가는 %s(천원)입니다.",
code, name,
format(round(stock.value, 0), big.mark=",")))
return(stock.value)
}
# 상대가치지표에 의한 평가
rel_value <- function(code, name){
# code <- "068270"; name <- "셀트리온"
# code <- "085660"; name <- "차바이오텍"
port.open()
# 시가총액/당기순이익
capital_result <- capital_beta(code, name)
data_is <- get_fin_is(code)
capital_result[,"당기순이익"] <- data_is[data_is[,"accode"]=="203170",ncol(data_is)]
capital_result[,"per"] <- capital_result[,"시가총액"]/capital_result[,"당기순이익"]
# 시가총액/자기자본
data_fs <- get_fin_fs(code)
capital_result[,"자본총계"] <- data_fs[data_fs[,"accode"]=="120000",ncol(data_fs)]
capital_result[,"pbr"] <- capital_result[,"시가총액"]/capital_result[,"자본총계"]
# 시가총액/영업현금흐름
data_cf <- get_fin_cf(code)
capital_result[,"영업활동으로인한현금흐름"] <-
data_cf[data_cf[,"accode"]=="400000",ncol(data_cf)]
capital_result[,"pcfr"] <-
capital_result[,"시가총액"]/capital_result[,"영업활동으로인한현금흐름"]
# 동일업종 종목들도 동일한 방식으로 구하기
dind <- stock_list_tot[stock_list_tot[,2]==code, 5]
ind_key <- c(dind)
stock_list <- stock_list_tot[stock_list_tot[,5]==ind_key, ]
capital_all <- data.frame()
for (i in 1:nrow(stock_list)){ # i <- 1
remDr$open()
ef <- as.character(c(stock_list[i,"종목코드"],stock_list[i,"기업명"]))
print(ef)
# 시가총액/당기순이익
capital_result <- try(capital_beta(ef[1], ef[2]), silent = T)
if( class(capital_result) == "try-error" ){
capital_result <- data.frame(
종목코드 = ef[1], 업체명 = ef[2], 베타=NA, 발행주식수=NA,
시가총액 = NA, 당기순이익 = NA, per = NA, 자본총계 = NA,
pbr = NA, 영업활동으로인한현금흐름 = NA, pcfr = NA
)
}else{
data_is <- get_fin_is(ef[1])
capital_result[,"당기순이익"] <- data_is[data_is[,"accode"]=="203170",ncol(data_is)]
capital_result[,"per"] <- capital_result[,"시가총액"]/capital_result[,"당기순이익"]
# 시가총액/자기자본
data_fs <- get_fin_fs(ef[1])
capital_result[,"자본총계"] <- data_fs[data_fs[,"accode"]=="120000",ncol(data_fs)]
capital_result[,"pbr"] <- capital_result[,"시가총액"]/capital_result[,"자본총계"]
# 시가총액/영업현금흐름
data_cf <- get_fin_cf(ef[1])
capital_result[,"영업활동으로인한현금흐름"] <-
data_cf[data_cf[,"accode"]=="400000",ncol(data_cf)]
capital_result[,"pcfr"] <-
capital_result[,"시가총액"]/capital_result[,"영업활동으로인한현금흐름"]
}
capital_all <- rbind(capital_all, capital_result)
remDr$close()
Sys.sleep(2)
}
port.close()
########################################################################################
# 업종별 PER, PBR, PCFR 구해서 개별 기업의 기업가치평가
# hist(capital_all[,"pbr"])
# hist(capital_all[,"per"])
# hist(capital_all[,"pcfr"])
# 업종별 PER, PBR, PCFR trimmed mean 구하기
mpbr <- mean(capital_all[,"pbr"], trim=0.2, na.rm=T)
mper <- mean(capital_all[capital_all[,"per"]>0,"per"], trim=0.2, na.rm=T)
mpcfr <- mean(capital_all[capital_all[,"pcfr"]>0,"pcfr"], trim=0.2, na.rm=T)
# 업종 주가 평가
market_value <- capital_all
market_value$mv_pbr <-
market_value[,"자본총계"] * mpbr / market_value[,"발행주식수"]*100000000
market_value$mv_per <-
market_value[,"당기순이익"] * mper/ market_value[,"발행주식수"]*100000000
market_value$mv_pcfr <-
market_value[,"영업활동으로인한현금흐름"] * mpcfr/ market_value[,"발행주식수"]*100000000
market_value$mv_pbr[market_value$mv_pbr<0] <- NA
market_value$mv_per[market_value$mv_per<0] <- NA
market_value$mv_pcfr[market_value$mv_pcfr<0] <- NA
return(market_value)
}
# 뉴스크롤링
news_crawl <- function(code, name, number=0){
# code <- "068270"; name <- "셀트리온"
# code <- "085660"; name <- "차바이오텍"
# URL 생성
url_naver_finance_news_code <-
"http://finance.naver.com/item/news_news.nhn?code=%s&page=%s"
page <- 1
r_url <- sprintf(url_naver_finance_news_code, code, page)
contents <- GET(r_url)
# 마지막 페이지를 가져오기
pg.last <- strsplit(read_html(contents) %>%
html_nodes("td.pgRR a") %>% html_attr("href"), "&")[[1]][2]
pg.last <- strsplit(pg.last, "=")[[1]][2]
# 0인 경우는 마지막 페이지 그렇지 않은 경우는 개수만큼 가져오기
if(number == 0){
pg.last <- pg.last
}else pg.last <- number
# loop 만들어서 url list 만들기
message("#################################################################\n",
"#################################################################\n",
sprintf("%s, %s의 URL을 수집합니다.\n", code, name))
page <- 1:pg.last
news_url <- c()
for (page_num in page){ # page <- 1
r_url <- sprintf(url_naver_finance_news_code, code, page_num)
contents <- GET(r_url)
html <- read_html(contents)
temp <- unique(html_nodes(html, "table") %>%
html_nodes("a") %>%
html_attr("href"))
news_url <- c(news_url, temp)
print(page_num)
}
# 기사 아이디가 존재하는 URL만 선택
news_url <- news_url[grepl("article_id=", news_url) == TRUE]
# 컨텐츠 수집
message("#################################################################\n",
"#################################################################\n",
sprintf("%s, %s의 컨텐츠를 수집합니다.\n", code, name))
news_content <- list()
for ( i in 1:length(news_url)){ # i <- 373
print(i)
n_url <- paste0("http://finance.naver.com",news_url[i])
contents <- GET(n_url)
html <- read_html(contents, encoding="euckr")
date <- html_nodes(html, xpath='//*[@class="tah p11"]')
date1 <- html_text(date)
html <- html_nodes(html, xpath='//*[@id="news_read"]')
temp <- html_text(html)
x <- gsub("[^A-Za-z가-힣[:space:][:digit:][:punct:]]", "", temp)
x <- gsub("@|\n|RT", "", x)
x <- gsub("[[:punct:]]", " ", x)
x <- gsub("[[:digit:]]", "", x)
x <- tolower(x)
x <- gsub("[a-z]", "", x)
x <- gsub("[\t\n]", "", x)
news <- cbind(date = date1, url = n_url, content = x)
news <- as.data.frame(news)
news_content[[length(news_content)+1]] <- news
}
# 출력 및 확인
return(news_content)
}
#########################################################################################################
# 0. 필요한 패키지 설치
setwd("C:/Users/user/Desktop/단기과정/corpvalue")
source("prescribed_0804.R")
#########################################################################################################
# 1. stockcrawl_last
stockcrawl_last("068270", "셀트리온")
#########################################################################################################
# 2. stockcrawl
tseries <- stockcrawl("068270", "셀트리온", 10)
plot(tseries)
#########################################################################################################
# 3. stockcrawl_adj
tseries_adj <- stockcrawl_adj_new("068270", "셀트리온",0)
plot(tseries_adj[,1])
#########################################################################################################
# 4. stock_code_list & stockcrawl_adj_new 반복적용
port.open()
ind_key <- c("전체")
stock_list_tot <- stock_code_list(ind_key)
ind_key <- c("의약", "의료", "생물")
stock_list <- stock_code_list(ind_key)
port.close()
stock_data <- data.frame()
for (i in 1:nrow(stock_list)){ # i <- 1
print(t(c(stock_list[i,"종목코드"], stock_list[i,"기업명"])))
temp <- stockcrawl_adj_new(stock_list[i,"종목코드"],
stock_list[i,"기업명"], 0)
temp1 <- data.frame(
종목코드 = as.character(stock_list[i,"종목코드"]),
기업명 = as.character(stock_list[i,"기업명"]),
temp[nrow(temp),])
row.names(temp1) <- NULL
stock_data <- rbind(stock_data, temp1)
}
#########################################################################################################
# 5. Tile Chart
## 업종코드 붙이기
sf1 <- as.data.frame(left_join(stock_data, stock_list))
## 전체에 대한 평균 수익률과 거래량 합 계산
sf2 <- data.frame(수익률 = weighted.mean(sf1[,5], sf1[,4]), 거래량 = sum(sf1[,4]))
## 중분류산업명별로 평균 수익률과 거래량 합 계산
sf3 <- sf1 %>% group_by(업종) %>%
summarise(수익률 = weighted.mean(수익률, 거래량), 거래량 = sum(거래량)) %>%
select(업종, 수익률, 거래량)
names(sf3) <- c("하위수준","수익률", "거래량")
## googleVis의 gvisTreeMap을 그리기 위해 데이터셋 생성
sf4 <- data.frame(상위수준 = NA, 하위수준 = "전체", sf2)
sf5 <- data.frame(상위수준 = "전체", sf3)
sf6 <- data.frame(상위수준=sf1[,8], 하위수준 = sf1[,2], sf1[,c(5,4)])
sf7 <- rbind(sf4, sf5, sf6)
# 색“Set1”에서 3가지 색을 가져와 col에 저장
col <- brewer.pal(3,"Set1")
## gvisTreeMap에 활용할 “,”로 연결된 문자객체 스트링 col1 생성
col1 <- paste(col,collapse=",")
## gvisTreeMap 함수를 이용하여 그림정보를 산출하고 Tree에 저장
Tree <- gvisTreeMap(data=sf7, idvar="하위수준", parentvar="상위수준", sizevar="거래량", colorvar="수익률",
options=list(width=1200, height=800,
fontSize=12,
colors=col1,
headerHeight=20,
fontColor='black',
showScale=TRUE))
## 해당 Tree는 인코딩 방식이 UTF-8로서 한글이 그림에
## 나타나게 하기 위해서는 Tree파일에 대한변환 수행
Tree$html$header <- gsub("utf-8", "euckr", Tree$html$header)
## 그림 출력(웹으로 출력)
plot(Tree)
########################################################################################
# 6. 개별기업 FCF 평가
# 매크로 지표 가져오기
data_macro <- macro_crawl()
market.return <- data_macro[1]
risk.free.rate <- data_macro[2]
# 개별기업 평가하기
data.fcf <- fcf_value("068270", "셀트리온", market.return, risk.free.rate)
data.fcf <- fcf_value("085660", "차바이오텍", market.return, risk.free.rate)
########################################################################################
# 7. 개별기업 PER, PBR, PCFR 가져오기
market_value <- rel_value("085660", "차바이오텍")
########################################################################################
# 8. 뉴스분석
news_content <- news_crawl("068270", "셀트리온",0)
# 워드클라우드 그리기
x <- news_content[[1]]
useNIADic()
x1 <- lapply(x, extractNoun)
x2 <- lapply(x1, function(x) x[nchar(x)>1])
x3 <- do.call(c, x2)
o <- table(x3)
pal <- brewer.pal(8,"Dark2")
wordcloud(names(o), o, min.freq=1, random.order=F,random.color=T,colors=pal,family="AppleGothic")
# 새로운 그림 창이 필요할 경우에는 dev.new()
########################################################################################
# 9. ESG 스코어 관계 분석
# 수정주가 가져와서 월말 수정주가 구하기
data.price.adj_new <- stockcrawl_adj_new("068270", "셀트리온", 0)
sadjm <- to.monthly(data.price.adj_new)[,4]
# ESG 스코어 구하기
# URL 생성
url_naver_finance_news_code <- "http://finance.naver.com/item/news_news.nhn?code=%s&page=%s"
# 네이버파이낸스에서 뉴스 가져오기
news_content <- news_crawl("068270", "셀트리온",0)
# 부정어휘 키워드 읽기
keyword <- read.xlsx2("ESG.xlsx", sheetIndex = 1)
kw <- keyword[,2]
# 명사만 추출하여 정리 -> 시간이 많이 소요됨
news_term <- lapply(news_content, extractNoun)
# 개별 뉴스의 어휘들로부터 부정어휘개수가 몇개인지를 카운트함
tf <- c()
date <- c()
for(i in 2019:length(news_content)){ # i <- 1
print(i)
tf[i] <- sum(sapply(kw, function(x) length(grep(x, news_term[[i]]))))
date[i] <- news_content[[i]][,1]
}
# 날짜와 부정어휘 숫자들을 데이터 프레임으로 생성
esg.data <- data.frame(date=date, tf=tf)
# 월별 스코어 만들기
# 날짜를 데이트형식으로 바꾸기
esg.data$date <- as.Date(substring(str_trim(esg.data$date),1,10), "%Y.%m.%d")
# 월별로 바꾸기
esg.data$month <- format(esg.data$date, "%Y.%m")
# 월별로 스코어 합 구하기
esg.data1 <- as.data.frame(esg.data %>% group_by(month) %>% summarise(sumtf = sum(tf)))
# 수정주가와 결합
sadjm1 <- as.numeric(sadjm)
month <- format(index(sadjm), "%Y.%m")
ss <- data.frame(month=month, adjp = sadjm1)
# 수정주가와 ESG스코어 결합
df1 <- inner_join(ss, esg.data1)
t1 <- as.Date(paste0(df1$month,".01"), "%Y.%m.%d")
month(t1) <- month(t1) + 1
t1 <- t1 -1
df1$date <- t1
# 패턴에 대한 확인
p1 <- ggplot(df1, aes(x=date, y=sumtf)) +
geom_line(color="red") + geom_point(color="red") +
ggtitle("ESG Score")
p2 <- ggplot(df1, aes(x=date, y=adjp)) +
geom_line(color="blue") + geom_point(color="blue") +
ggtitle("adjusted price")
grid.arrange(p1, p2, nrow = 2)
# 회귀분석 수행
model <- lm(df1$adjp ~ lag(df1$sumtf,3))
summary(model)
# 전체파일 저장하기
save.image("temp.Rdata")
# 전체파일 불러들이기
load("temp.Rdata")