Post List

R을 이용한 퀀트 투자 포트폴리오 만들기





질문은 웹북에 남겨주시기 바랍니다.


[CHAPTER 1 퀀트 투자의 심장: 데이터와 프로그래밍]

1.1 데이터 구하기 003
1.2 퀀트 투자와 프로그래밍 005
1.3 R 프로그램 006
1.4 퀀트 투자에 유용한 R 패키지 008



[CHAPTER 2 크롤링을 위한 기본 지식]
2.1 인코딩의 이해와 R에서 UTF-8 설정하기 012
__2.1.1 인간과 컴퓨터 간 번역의 시작, ASCII 012
__2.1.2 한글 인코딩 방식의 종류 013
__2.1.3 R에서 UTF-8 설정하기 014
2.2 웹의 동작 방식 015
__2.2.1 HTTP 016
2.3 HTML과 CSS 017
__2.3.1 HTML 기본 구조 018
__2.3.2 태그와 속성 019
__2.3.3 h 태그와 p 태그 019
__2.3.4 리스트를 나타내는 ul 태그와 ol 태그 020
__2.3.5 table 태그 021
__2.3.6 a 태그와 src 태그 및 속성 023
__2.3.7 div 태그 024
__2.3.8 CSS 025
__2.3.9 클래스와 id 026
2.4 파이프 오퍼레이터(%〉%) 028
2.5 오류에 대한 예외처리 031



[CHAPTER 3 API를 이용한 데이터 수집]
3.1 API를 이용한 Quandl 데이터 다운로드 034
3.2 getSymbols() 함수를 이용한 API 다운로드 035
__3.2.1 주가 다운로드 036
__3.2.2 국내 종목 주가 다운로드 039
__3.2.3 FRED 데이터 다운로드 041



[CHAPTER 4 크롤링 이해하기]
4.1 GET과 POST 방식 이해하기 046
__4.1.1 GET 방식 046
__4.1.2 POST 방식 048
4.2 크롤링 예제 050
__4.2.1 금융 속보 크롤링 050
__4.2.2 기업공시채널에서 오늘의 공시 불러오기 053
__4.2.3 네이버 금융에서 주식티커 크롤링 056



[CHAPTER 5 금융 데이터 수집하기(기본)]
5.1 한국거래소의 산업별 현황 및 개별지표 크롤링 067
__5.1.1 산업별 현황 크롤링 068
__5.1.2 개별종목 지표 크롤링 071
__5.1.3 최근 영업일 기준 데이터 받기 073
__5.1.4 거래소 데이터 정리하기 077
5.2 WICS 기준 섹터 정보 크롤링 083



[CHAPTER 6 금융 데이터 수집하기(심화)]
6.1 수정주가 크롤링 089
__6.1.1 개별종목 주가 크롤링 090
__6.1.2 전 종목 주가 크롤링 095
6.2 재무제표 및 가치지표 크롤링 097
__6.2.1 재무제표 다운로드 097
__6.2.2 가치지표 계산하기 102
__6.2.3 전 종목 재무제표 및 가치지표 다운로드 107
6.3 야후 파이낸스 데이터 구하기 110
__6.3.1 재무제표 다운로드 111
__6.3.2 가치지표 계산하기 115



[CHAPTER 7 데이터 정리하기]
7.1 주가 정리하기 119
7.2 재무제표 정리하기 121
7.3 가치지표 정리하기 125



[CHAPTER 8 데이터 분석 및 시각화하기]
8.1 종목정보 데이터 분석 130
__8.1.1 *_join(): 데이터 합치기 130
__8.1.2 glimpse(): 데이터 구조 확인하기 132
__8.1.3 rename(): 열 이름 바꾸기 133
__8.1.4 distinct(): 고유한 값 확인 134
__8.1.5 select(): 원하는 열만 선택 135
__8.1.6 mutate(): 열 생성 및 데이터 변형 136
__8.1.7 filter(): 조건을 충족하는 행 선택 137
__8.1.8 summarize(): 요약 통곗값 계산 138
__8.1.9 arrange(): 데이터 정렬 138
__8.1.10 row_number(): 순위 계산 139
__8.1.11 ntile(): 분위수 계산 140
__8.1.12 group_by(): 그룹별로 데이터를 묶기 141
8.2 종목정보 시각화 142
__8.2.1 geom_point(): 산점도 나타내기 144
__8.2.2 geom_histogram(): 히스토그램 나타내기 146
__8.2.3 geom_boxplot(): 박스 플롯 나타내기 147
__8.2.4 dplyr과 ggplot을 연결해 사용하기 148
__8.2.5 geom_bar(): 막대 그래프 나타내기 150
8.3 주가 및 수익률 시각화 152
__8.3.1 주가 그래프 나타내기 152
__8.3.2 인터랙티브 그래프 나타내기 154
__8.3.3 연도별 수익률 나타내기 157



[CHAPTER 9 퀀트 전략을 이용한 종목 선정(기본)]
9.1 베타 이해하기 163
__9.1.1 베타 계산하기 165
__9.1.2 베타 시각화 167
9.2 저변동성 전략 168
__9.2.1 저변동성 포트폴리오 구하기: 일간 기준 170
__9.2.2 저변동성 포트폴리오 구하기: 주간 기준 173
9.3 모멘텀 전략 176
__9.3.1 모멘텀 포트폴리오 구하기: 12개월 모멘텀 176
__9.3.2 모멘텀 포트폴리오 구하기: 위험조정 수익률 178
9.4 밸류 전략 181
__9.4.1 밸류 포트폴리오 구하기: 저PBR 182
__9.4.2 각 지표 결합하기 183
9.5 퀄리티 전략 186
__9.5.1 F-Score 지표 186
__9.5.2 각 지표 결합하기 191



[CHAPTER 10 퀀트 전략을 이용한 종목 선정(심화)]
10.1 섹터 중립 포트폴리오 195
10.2 마법공식 199
__10.2.1 퀄리티와 밸류 간의 관계 200
__10.2.2 마법공식 이해하기 202
__10.2.3 마법공식 구성하기 203
10.3 이상치 데이터 제거 및 팩터의 결합 206
__10.3.1 트림(Trim): 이상치 데이터 삭제 208
__10.3.2 윈저라이징(Winsorizing): 이상치 데이터 대체 209
__10.3.3 팩터의 결합 방법 210
10.4 멀티팩터 포트폴리오 212



[CHAPTER 11 포트폴리오 구성]
11.1 최소분산 포트폴리오 224
__11.1.1 slsqp() 함수를 이용한 최적화 224
__11.1.2 solve.QP() 함수를 이용한 최적화 228
__11.1.3 optimalPortfolio() 함수를 이용한 최적화 233
__11.1.4 결괏값들의 비교 235
__11.1.5 최소 및 최대 투자비중 제약조건 236
__11.1.6 각 자산별 제약조건의 추가 239
11.2 최대분산효과 포트폴리오 241
__11.2.1 solve.QP() 함수를 이용한 최적화 244
__11.2.2 optimalPortfolio() 함수를 이용한 최적화 246
__11.2.3 최소 및 최대 투자비중 제약조건 247
__11.2.4 각 자산별 제약조건의 추가 250
11.3 위험균형 포트폴리오 252
__11.3.1 주식 60%와 채권 40% 포트폴리오의 위험기여도 253
__11.3.2 rp() 함수를 이용한 최적화 254
__11.3.3 위험예산 포트폴리오 256



[CHAPTER 12 포트폴리오 백테스트]
12.1 Return.portfolio() 함수 260
__12.1.1 인자 목록 살펴보기 260
__12.1.2 출력값 살펴보기 262
12.2 전통적인 60대 40 포트폴리오 백테스트 262
12.3 시점 선택 전략 백테스트 267
12.4 동적 자산배분 백테스트 273



[CHAPTER 13 성과 및 위험 평가]
13.1 결과 측정 지표 284
__13.1.1 수익률 및 변동성 284
__13.1.2 낙폭과 최대낙폭 288
__13.1.3 연도별 수익률 290
__13.1.4 승률 및 롤링 윈도우 값 292
13.2 팩터 회귀분석 및 테이블로 나타내기 294


댓글 24개:

  1. 안녕하세요! 출판하신 책 보면서 하나씩 코드 따라치며 쫒아가고 있는 학생입니다 ㅎㅎ
    덕분에 정말 많이 배우고 있습니다!!
    다름이 아니라, 이번에 dart 오픈 API가 리뉴얼 되면서 방식이 조금 바뀐거 같더라구요. 혼용이 되는 거 같기는 한데 혹시 새롭게 리뉴얼 된 API 관련해서도 글 올리실 생각이 있으신가요??
    바쁘시겠지만 올려주시면 정말 감사드릴 것 같습니다. 아 그리고 책에 있는 방식 참고해서 url의 기초만 되는 주소랑 인자명만 바꿔서 하니까 데이터 불러오기는 잘 되는거 같습니다 ㅎㅎ 책 잘 읽고 있어요!!

    답글삭제
    답글
    1. 코드는 다짰는데 글쓸 시간이 없어서요..

      삭제
    2. 저도 감사하게 코드를 활용하고 있습니다. 모든게 잘 돌아가는데, 윗분처럼 Dart와 제무제표 다운로드에 막혀서 헤매고 있습니당.책은 잘 보고 있습니당

      삭제
  2. 안녕하세요.
    책 구입해서 읽다가 인사드리러 왔습니다.
    앞으로 궁금한거 있으면 많은 글 올리겠습니다.
    좋은 책 만들어주셔서 감사합니다.

    답글삭제
  3. 책 정말 잘보고있습니다. 고배당 전략 관련 내용도 추가해주세요.. 감사합니다.

    답글삭제
  4. 선생님 안녕하세요? 책 정말 잘보고 있습니다.
    하나 문의드릴게 있는데 연락드릴 방도를 몰라 여기다 글을 남깁니다.
    처음에 책따라서 해볼때는 잘되었는데 최근에 갑자기 안되는게 있어서요
    만드신 함수중에 get_KOR_fs 함수가 잘 동작 하시나요?
    저는 만드신 함수도 안되고 따라서 해본 제 소스도 안되고....
    "http://comp.fnguide.com" 사이트에 GET(url)부터 안되는거 같은데 이유를 모르겠어서 글을 좀 남깁니다.
    혹여나 여유가 되시면 잘 되는지 확인 한번만 부탁드립니다.

    답글삭제
    답글
    1. 안녕하세요 저도 좋은 책 만들어 주셔서 잘 보고 있습니다.
      저도 동일한 부분에서 안 되네요.

      교재의 97~98 페이지에 있는 코드에서 에러가 납니다.

      url <- paste0('http://comp.fnguide.com/SVO2/ASP/SVD_Finance.asp?pGB=1&gicode=A005930')
      data <- GET(url)
      Error in curl::curl_fetch_memory(url, handle = handle) :
      Recv failure: Connection was reset

      삭제
    2. 사이트가 크롤로러 접근하는걸 막았네요
      웹페이지 접속인척 속여주면 됩니다

      url = paste0('http://comp.fnguide.com/SVO2/ASP/SVD_Finance.asp?pGB=1&gicode=A005930')

      headers = c(
      'User-Agent' = 'Mozilla/5.0'
      )

      data = GET(url, add_headers(.headers=headers))

      header 라는 부분을 통해 마치 모질라 웹페이지로 접속한것 처럼 신호를 보내면 문제없이 작동합니다.

      삭제
    3. 와 답변 감사드립니다! header를 추가하니 잘 작동이 되네요!
      추가적으로 궁금한게 있는데, 해당 사이트가 크롤러 접속을 막았을 때 어떤 헤더를 붙여야 할지 구분할 수 있는
      팁이 있을까요??
      개발자도구의 Request headers에 있는
      ==============================================================
      User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36
      ==============================================================
      위 부분 때문에 그런거 같은데 맞나요??

      삭제
    4. 무차별한데 개발자들이 모질라를 많이 써서 그런지 대부분 모질라나 크롬을 붙입니다.

      삭제
  5. 안녕하십니까, 책 정말 잘 읽고있는데 궁금한 점이 있어 댓글남겨봅니다.
    이번에 dart가 오픈dart로 바뀌면서,, 다운로드를 못받고 있습니다.
    이거를 어떡해야 다운로드가 가능할까요? ㅜㅜ.. 인증키를 받아도, 미등록 사용자라고 뜨며 진행이 불가능합니다.
    또, 그거 없이 해도 별 지장은 없을까요?

    답글삭제
    답글
    1. DART 애초에 인쇄본에 있던 내용도 아니고, 그냥 문의가 많아서 서비스로 올린겁니다.

      삭제
  6. 혹시 사이트가 UTF인지 EUC코딩인지 어떤 코딩형식으로 이루어졌는지 알아볼 수 있는 방법이 있나요?

    답글삭제
    답글
    1. 변수 = GET('url') 이나 POST('url') 한다음에 print(변수) 해보시면 charset 에 나와있습니다.

      삭제
  7. 크롤링을 했는데 그 값이 빈칸( )일 경우 숫자 0으로 표현하고 싶은데 어떻게 해야하나요?
    아래처럼 코드 넣었떠니 오류가 계속 뜨네요
    price = read_html(data) %>%
    html_node(xpath = '//*[@id="svdMainChartTxt11"]') %>%
    html_text() %>%
    parse_number()

    답글삭제
    답글
    1. 어떤 종목인지 알려주셔야..

      삭제
    2. 예를 들어 http://comp.fnguide.com/ 스냅샷에서
      삼성전자 주주구분현황 중 자기주식-보통주 부분이 빈칸으로 되어 있는데 자료로는 0으로 표현하고 싶습니다.
      share = read_html(data) %>%
      html_node(xpath = '//*[@id="svdMainGrid5"]/table/tbody/tr[5]/td[2]') %>%
      html_text() %>%
      parse_number()

      삭제
    3. ifelse(is.na(share), 0, share) 이런식으로 가능하죠

      삭제
  8. 안녕하세요~ 좋은 자료 너무 감사합니다.

    다름이아니라 5장에서 거래소자료를 다운받는 아래의 코드 실행시
    down_sector = POST(down_url, query = list(code = otp), add_headers(referer = gen_otp_url)) %>%
    read_html() %>% html_text() %>% read_csv()

    이런 오류가 뜨는데요....
    Error: '일자,종목코드,종목명,관리여부,종가,EPS,PER,BPS,PBR,주당배당금,배당수익률,게시물 일련번호,총카운트' does not exist in current working directory

    혹시 거래소의 데이터 정책이 바뀌어서 나는 오류인가요??

    답글삭제
    답글
    1. 아뇨. schdate에 비영업일 입력하시면 나오는 오류입니다.

      삭제
  9. ★ 질문은 웹북 해당 챕터에 남겨주시기 바랍니다.★
    https://hyunyulhenry.github.io/quant_cookbook/

    답글삭제
  10. 안녕하세요... 패스트 캠퍼스에서 강의를 듣고 있습니다.
    전 종목 크롤링할때 아래와 같은 에러가 발생합니다.

    # 데이터 나누기
    + price = read_delim(data_html, delim = '|')
    +
    + # 필요한 열만 선택 후 클렌징
    에러: 구문분석중 라인 24에서 유효하지 않은 멀티바이트 문자를 찾았습니다
    > price = price[c(1, 5)]
    에러: 객체 'price'를 찾을 수 없습니다
    > price = data.frame(price)
    Error in data.frame(price) : 객체 'price'를 찾을 수 없습니다
    > colnames(price) = c('Date', 'Price')
    Error in colnames(price) = c("Date", "Price") :
    객체 'price'를 찾을 수 없습니다
    > price[, 1] = ymd(price[, 1])
    Error in lapply(list(...), .num_to_date) :
    객체 'price'를 찾을 수 없습니다
    >
    > rownames(price) = price[, 1]
    에러: 객체 'price'를 찾을 수 없습니다
    > price[, 1] = NULL
    Error in price[, 1] = NULL : 객체 'price'를 찾을 수 없습니다
    >
    > }, error = function(e) {
    에러: 예기치 않은 '}'입니다 in " }"
    >
    > # 오류 발생시 해당 종목명을 출력하고 다음 루프로 이동
    > warning(paste0("Error in Ticker: ", name))
    Error in paste0("Error in Ticker: ", name) :
    객체 'name'를 찾을 수 없습니다
    > })
    에러: 예기치 않은 '}'입니다 in " }"
    >
    > # 다운로드 받은 파일을 생성한 폴더 내 csv 파일로 저장
    > write.csv(price, paste0('data/KOR_price/', name,
    + '_price.csv'))
    Error in is.data.frame(x) : 객체 'price'를 찾을 수 없습니다
    >
    > # 타임슬립 적용
    > Sys.sleep(2)
    > }
    에러: 예기치 않은 '}'입니다 in "}"

    1, 어떻게 해야하는지 모르겠습니다.
    2. 그리고 패스트캠퍼스에서 R프로그래밍 기초에서 공유해신 파일은 어디서 받을 수 있나요?

    답글삭제
  11. 웹북 해당 챕터에도 글을 남겼었는데..자꾸 글이 사라지는거 같습니다.

    답글삭제