Post List

2018년 3월 21일 수요일

HenryQuant 패키지를 이용한 국내 F-Score + Value Investing




library(HenryQuant)
library(dplyr)
library(magrittr)

get_KOR_fs2()
fs = arrange_KOR_fs()

먼저 핵심 패키지인 HenryQuant
데이터정리에 필요한 dplyr, magrittr 패키지를 불러옵니다.

그 후, HenryQuant 패키지의 get_KOR_fs2 함수를 이용해
전종목 재무데이터 및 밸류데이터를 다운 받고,

arrange_KOR_fs 함수를 통해 재무데이터를 항목별로 정리합니다.
정리된 재무데이터는 fs 변수에 지정합니다.




KOR_fs_2 폴더에는 전종목 재무데이터가,
KOR_value 폴더에는 전종목 밸류데이터가,
KOR_fs_list.csv는 정리된 재무데이터가,
KOR_value_list.csv는 정리된 밸류데이터가

각각 저장됩니다.





fs 변수는 list 형태로 저장되며, 내용을 확인해보면
각 항목별로 2312개 종목의 데이터가 정리되어 있습니다.




F_Score_Table = function(fs) {
  
  ticker_list = rownames(fs[[1]])
  n = ncol(fs[[1]])
  
  ROA = fs$'계속영업이익' / fs$'자산'
  CFO = fs$'영업활동으로인한현금흐름' / fs$'자산'
  ACCURUAL = CFO - ROA
  
  LEV = fs$'장기차입금' / fs$'자산'
  LIQ = fs$'유동자산' / fs$'유동부채'
  OFFER = fs$'유상증자'
  OFFER[is.na(OFFER)] = 0
  MARGIN = fs$'매출총이익' / fs$'매출액'
  TURN = fs$'매출액' / fs$'자산'
  
  F_Table = data.frame(matrix(NA, length(ticker_list), 9))
  F_Table[, 1] = as.integer(ROA[,n] > 0)
  F_Table[, 2] = as.integer(CFO[,n] > 0)
  F_Table[, 3] = as.integer(ROA[,n] - ROA[,(n-1)] > 0)
  F_Table[, 4] = as.integer(ACCURUAL[,n] > 0)
  F_Table[, 5] = as.integer(LEV[,n] - LEV[,(n-1)] <= 0)
  F_Table[, 6] = as.integer(LIQ[,n] - LIQ[,(n-1)] > 0)
  F_Table[, 7] = as.integer(OFFER[,n] == 0)
  F_Table[, 8] = as.integer(MARGIN[,n] - MARGIN[,(n-1)] > 0)
  F_Table[, 9] = as.integer(TURN[,n] - TURN[,(n-1)] > 0)
  
  item = c("ROA", "CFO", "D ROA", "Accrual", "D Leverage", "D Liquidity",
           "Offer", "D Margin", "D Turnover")
  colnames(F_Table) = item
  rownames(F_Table) = ticker_list
  
  F_score = apply(F_Table, 1, sum, na.rm = TRUE) %>%
    as.data.frame %>%
    set_rownames(ticker_list) %>%
    set_colnames("F-Score")
  
  return(F_score)
}


정리된 변수인 fs를 활용하여 전종목의 F Score를 계산하는 
F_Score_Table 명령어를 만들어 줍니다.

원 논문에서 OFFER의 경우 신주발행 유무이지만,
해당 데이터를 구할 수 있는 방법이 없어
유상증자 유무로 변경하였습니다.

즉, 유상증자를 하였으면 0점, 아니면 1점으로 대체합니다.



F_Score = F_Score_Table(fs)




해당 함수를 실행하면, 각 종목별로 F Score가 나타납니다.




rownames(F_Score)[which(F_Score == 9)]



요런식으로 원하는 점수의 종목만 뽑을수도 있습니다.





F_Score_value = function(fs, score = c(8, 9), n = 30) {
  
  F_Score = F_Score_Table(fs)
  value = read.csv("KOR_value_list.csv", row.names = 1)
  value = value[,c(1,4,5)]
  
  if (all.equal(rownames(F_Score), rownames(value)) != TRUE) {
    stop("Rownames of F_Score and Value is not same")
  }
  
  x = rownames(value)
  value = apply(value, 2, as.numeric) %>% set_rownames(x)
  
  target = c()
  for (k in 1 : length(score)) {
    temp = which(F_Score == score[k])
    target = append(target, temp)
  }
  target = target %>% sort
  
  rank1 = value[target, 1]  %>% rank
  rank2 = value[target, 2]  %>% rank
  rank3 = -value[target, 3]  %>% rank
  
  x = target[(cbind(rank1,rank2,rank3) %>% rowSums %>% rank) <= n]
  
  fscore_bind = cbind(F_Score, value)
  res = list(
    TICKER = fscore_bind[x,] %>% rownames,
    DETAIL = round(fscore_bind[x,], 3)
  )
  
  print(res)
  return(res)
  
}


다음은 원하는 점수의 F Score 기준
상위 밸류 n 종목을 선택하는 명령어 입니다.


디폴트로 score 에는 8점과 9점이,
종목수는 30 종목이 선택되어 있습니다.

밸류는 PER, PBR, DY의 순위를 기준으로 합니다.




Final = F_Score_value(fs, score = c(8, 9), n = 30)




만들어진 함수를 실행해 봅니다.
Final은 list 형태로 저장되어

[[1]] 번째에는 해당 기준에 부합하는 종목의 티커가,
[[2]] 번째에는 해당 종목의 F_Score, PER, PBR, DY가 나타납니다.

물론 결과물이 자동으로 출력되기도 합니다.






댓글 1개: