Skip to content

Commit

Permalink
Update book
Browse files Browse the repository at this point in the history
  • Loading branch information
hyunyulhenry committed Mar 16, 2020
1 parent 55f53f4 commit 6e8fe86
Show file tree
Hide file tree
Showing 264 changed files with 38,170 additions and 17,889 deletions.
8 changes: 4 additions & 4 deletions 02-information.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,9 @@ knitr::kable(
),
booktabs = TRUE,
align = "c",
caption = 'HTTP 요청 방식과 설명'
caption = 'HTTP 요청 방식과 설명',
) %>%
kableExtra::kable_styling(latex_options = c("striped", "hold_position")) %>%
kableExtra::column_spec(2, width = "5cm")
kableExtra::kable_styling(latex_options = c("striped", "hold_position"))
```

인터넷을 사용하다 보면 한 번쯤 ‘이 페이지를 볼 수 있는 권한이 없음(HTTP 오류 403 - 사용할 수 없음)’ 혹은 ‘페이지를 찾을 수 없음(HTTP 오류 404 - 파일을 찾을 수 없음)’이라는 오류를 본 적이 있을 겁니다. 여기서 403과 404라는 숫자는 클라이언트의 요청에
Expand All @@ -97,7 +96,8 @@ knitr::kable(
),
booktabs = TRUE,
align = "c",
caption = 'HTTP 상태 코드 그룹 별 내용'
caption = 'HTTP 상태 코드 그룹 별 내용',
escape = FALSE
) %>%
kableExtra::kable_styling(latex_options = c("striped", "hold_position"))
```
Expand Down
3 changes: 1 addition & 2 deletions 03-api.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@ knitr::include_graphics('images/api_apple_csv.png')
그러나 웹 브라우저에 해당 주소를 입력해 csv 파일을 다운로드하고 csv 파일을 다시 R에서 불러오는 작업은 무척이나 비효율적입니다. R에서 API 주소를 이용해 직접 데이터를 다운로드할 수 있습니다.

```{r}
url.aapl = "https://www.quandl.com/api/v3/datasets/WIKI/AAPL/
data.csv?api_key=xw3NU3xLUZ7vZgrz5QnG"
url.aapl = "https://www.quandl.com/api/v3/datasets/WIKI/AAPL/data.csv?api_key=xw3NU3xLUZ7vZgrz5QnG"
data.aapl = read.csv(url.aapl)
head(data.aapl)
Expand Down
511 changes: 188 additions & 323 deletions 05-crawling_practice.Rmd

Large diffs are not rendered by default.

593 changes: 593 additions & 0 deletions 06-crawling_actual.Rmd

Large diffs are not rendered by default.

37 changes: 32 additions & 5 deletions 07-bind_data.Rmd
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
# 데이터 정리하기

```{r echo = FALSE, warning = FALSE, message = FALSE}
library(magrittr)
library(dplyr)
KOR_ticker = read.csv('data/KOR_ticker.csv', row.names = 1)
```

앞 CHAPTER에서는 API와 크롤링을 통해 주가, 재무제표, 가치지표를 수집하는 방법을 배웠습니다. 이번 CHAPTER에서는 각각 csv 파일로 저장된 데이터들을 하나로 합친 후 저장하는 과정을 살펴보겠습니다.

## 주가 정리하기

주가는 data/KOR_price 폴더 내에 티커_price.csv 파일로 저장되어 있습니다. 해당 파일들을 불러온 후 데이터를 묶는 작업을 통해 하나의 파일로 합치는 방법을 알아보겠습니다.

```{r message = FALSE, warning = FALSE}
```{r message = FALSE, warning = FALSE, eval = FALSE}
library(stringr)
library(xts)
library(magrittr)
Expand All @@ -29,8 +36,16 @@ for (i in 1 : nrow(KOR_ticker)) {
price_list = do.call(cbind, price_list) %>% na.locf()
colnames(price_list) = KOR_ticker$'종목코드'
```

```{r echo = FALSE}
# 저장된 데이터 불러오기
price_list = read.csv('data/KOR_price.csv')
```

```{r}
head(price_list[, 1:5])
tail(price_list[, 1:5])
```

1. 티커가 저장된 csv 파일을 불러온 후 티커를 6자리로 맞춰줍니다.
Expand All @@ -42,7 +57,7 @@ head(price_list[, 1:5])

해당 작업을 통해 개별 csv 파일로 흩어져 있던 가격 데이터가 하나의 데이터로 묶이게 됩니다.

```{r}
```{r eval = FALSE}
write.csv(data.frame(price_list), 'data/KOR_price.csv')
```

Expand All @@ -52,7 +67,7 @@ write.csv(data.frame(price_list), 'data/KOR_price.csv')

재무제표는 data/KOR_fs 폴더 내 티커_fs.csv 파일로 저장되어 있습니다. 주가는 하나의 열로 이루어져 있어 데이터를 정리하는 것이 간단했지만, 재무제표는 각 종목별 재무 항목이 모두 달라 정리하기 번거롭습니다.

```{r message = FALSE}
```{r message = FALSE, eval = FALSE}
library(stringr)
library(magrittr)
library(dplyr)
Expand All @@ -71,6 +86,15 @@ for (i in 1 : nrow(KOR_ticker)){
}
```

```{r eval = FALSE, echo = FALSE}
saveRDS(data_fs, 'data/data_fs.Rds')
```

```{r echo = FALSE}
# 저장된 데이터 불러오기
data_fs = readRDS('data/data_fs.Rds')
```

위와 동일하게 티커 데이터를 읽어옵니다. 이를 바탕으로 종목별 재무제표 데이터를 읽어온 후 리스트에 저장합니다.

```{r}
Expand Down Expand Up @@ -121,7 +145,7 @@ print(head(select_fs))

해당 과정을 통해 전 종목의 매출액 데이터가 연도별로 정리되었습니다. for loop 구문을 이용해 모든 재무 항목에 대한 데이터를 정리하는 방법은 다음과 같습니다.

```{r}
```{r eval = FALSE}
fs_list = list()
for (i in 1 : length(fs_item)) {
Expand Down Expand Up @@ -160,7 +184,7 @@ names(fs_list) = fs_item

위 과정을 거치면 fs_list에 총 `r length(fs_item)`리스트가 생성됩니다. 각 리스트에는 해당 재무 항목에 대한 전 종목의 연도별 데이터가 정리되어 있습니다.

```{r}
```{r eval = FALSE}
saveRDS(fs_list, 'data/KOR_fs.Rds')
```

Expand Down Expand Up @@ -226,7 +250,10 @@ data_value = data_value %>%
rownames(data_value) = KOR_ticker[, '종목코드']
print(head(data_value))
```


```{r eval = FALSE}
write.csv(data_value, 'data/KOR_value.csv')
```

Expand Down
21 changes: 17 additions & 4 deletions 09-factor_basic.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -552,7 +552,11 @@ TURN = KOR_fs$'매출액' / KOR_fs$'자산'
다음으로 각 지표들이 조건을 충족하는지 여부를 판단해, 지표별로 1점 혹은 0점을 부여합니다.

```{r}
num_col = ncol(KOR_fs[[1]])
if ( lubridate::month(Sys.Date()) %in% c(1,2,3,4) ) {
num_col = ncol(KOR_fs[[1]]) - 1
} else {
num_col = ncol(KOR_fs[[1]])
}
F_1 = as.integer(ROA[, num_col] > 0)
F_2 = as.integer(CFO[, num_col] > 0)
Expand All @@ -567,7 +571,7 @@ F_8 = as.integer(MARGIN[, num_col] -
F_9 = as.integer(TURN[,num_col] - TURN[,(num_col-1)] > 0)
```

`ncol()` 함수를 이용해 열 개수를 구해줍니다. 가장 최근년도의 재무제표가 가장 오른쪽에 위치하고 있으므로, 해당 변수를 통해 최근년도 데이터만을 선택할 수 있습니다.
`ncol()` 함수를 이용해 열 개수를 구해줍니다. 가장 최근년도의 재무제표가 가장 오른쪽에 위치하고 있으므로, 해당 변수를 통해 최근년도 데이터만을 선택할 수 있습니다. **그러나 1월~4월의 경우 전년도 재무제표가 일부만 들어오는 경향이 있으므로, 을 통해 전전년도 데이터를 사용해야 합니다.** 따라서 `Sys.Date()` 함수를 통해 현재 날짜를 추출한 후, lubridate 패키지의 `month()` 함수를 이용해 해당 월을 계산합니다. 만일 현재 날짜가 1~4월 일 경우 `ncol(KOR_fs[[1]]) - 1`을 이용해 전전년도 데이터를 선택하며, 그렇지 않을 경우(5~12월) 전년도 데이터를 선택합니다.

`as.integer()` 함수는 TRUE일 경우 1을 반환하고 FALSE일 경우 0을 반환하는 함수로서, F-Score 지표의 점수를 매기는 데 매우 유용합니다. 점수 기준은 다음과 같습니다.

Expand Down Expand Up @@ -631,10 +635,18 @@ library(tidyr)
KOR_fs = readRDS('data/KOR_fs.Rds')
KOR_ticker = read.csv('data/KOR_ticker.csv', row.names = 1,
stringsAsFactors = FALSE)
KOR_ticker$'종목코드' =
str_pad(KOR_ticker$'종목코드', 6, 'left', 0)
```

```{r}
if ( lubridate::month(Sys.Date()) %in% c(1,2,3,4) ) {
num_col = ncol(KOR_fs[[1]]) - 1
} else {
num_col = ncol(KOR_fs[[1]])
}
num_col = ncol(KOR_fs[[1]])
quality_roe = (KOR_fs$'지배주주순이익' / KOR_fs$'자본')[num_col]
quality_gpa = (KOR_fs$'매출총이익' / KOR_fs$'자산')[num_col]
quality_cfo =
Expand All @@ -645,7 +657,8 @@ quality_profit =
setNames(., c('ROE', 'GPA', 'CFO'))
```

먼저 재무제표와 티커 파일을 불러온 후 세 가지 지표에 해당하는 값을 구한 뒤 최근년도 데이터만 선택합니다. 그런 다음 `cbind()` 함수를 이용해 지표들을 하나로 묶어줍니다.
먼저 재무제표와 티커 파일을 불러온 후 세 가지 지표에 해당하는 값을 구한 뒤 최근년도 데이터만 선택합니다. 그런 다음 `cbind()` 함수를 이용해 지표들을 하나로 묶어줍니다. **역시나 1~4월의 경우 `ncol(KOR_fs[[1]]) - 1 `를 통해 보수적으로 전년도가 아닌 전전녀도 회계 데이터를 사용합니다.**


```{r}
rank_quality = quality_profit %>%
Expand Down
22 changes: 19 additions & 3 deletions 10-factor_adv.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,15 @@ KOR_ticker = read.csv('data/KOR_ticker.csv', row.names = 1,
stringsAsFactors = FALSE)
data_pbr = KOR_value['PBR']
if ( lubridate::month(Sys.Date()) %in% c(1,2,3,4) ) {
num_col = ncol(KOR_fs[[1]]) - 1
} else {
num_col = ncol(KOR_fs[[1]])
}
data_gpa =
(KOR_fs$'매출총이익' / KOR_fs$'자산')[ncol(KOR_fs[[1]])] %>%
(KOR_fs$'매출총이익' / KOR_fs$'자산')[num_col] %>%
setNames('GPA')
cbind(data_pbr, -data_gpa) %>%
Expand Down Expand Up @@ -223,7 +230,11 @@ KOR_ticker = read.csv('data/KOR_ticker.csv', row.names = 1,
KOR_ticker$'종목코드' =
str_pad(KOR_ticker$'종목코드', 6, 'left', 0)
num_col = ncol(KOR_fs[[1]])
if ( lubridate::month(Sys.Date()) %in% c(1,2,3,4) ) {
num_col = ncol(KOR_fs[[1]]) - 1
} else {
num_col = ncol(KOR_fs[[1]])
}
# 분자
magic_ebit = (KOR_fs$'지배주주순이익' + KOR_fs$'법인세비용' +
Expand Down Expand Up @@ -423,7 +434,12 @@ KOR_ticker$'종목코드' =
먼저 재무제표, 가치지표, 주가 데이터를 불러옵니다.

```{r warning = FALSE, message = FALSE, out.width='50%'}
num_col = ncol(KOR_fs[[1]])
if ( lubridate::month(Sys.Date()) %in% c(1,2,3,4) ) {
num_col = ncol(KOR_fs[[1]]) - 1
} else {
num_col = ncol(KOR_fs[[1]])
}
quality_roe = (KOR_fs$'지배주주순이익' / KOR_fs$'자본')[num_col]
quality_gpa = (KOR_fs$'매출총이익' / KOR_fs$'자산')[num_col]
quality_cfo =
Expand Down
31 changes: 5 additions & 26 deletions 11-portfolio.Rmd
Original file line number Diff line number Diff line change
@@ -1,29 +1,3 @@
```{r include=FALSE, cache=FALSE}
set.seed(123)
knitr::opts_chunk$set(
out.width = "70%",
fig.align = 'center',
fig.width = 6,
fig.asp = 0.618, # 1 / phi
fig.show = 'hold',
warning = FALSE,
message = FALSE
)
if(!knitr:::is_html_output()) {
options("width"=56)
knitr::opts_chunk$set(
warning = FALSE,
message = FALSE
)
knitr::opts_chunk$set(fig.pos = 'h')
}
pdf.options(family = "Korea1deb")
options(scipen = 5)
options(digits = 4)
```
# 포트폴리오 구성

종목별로 비중을 어떻게 배분하느냐에 따라 성과가 달라지므로, 종목의 선택 못지 않게 중요한 것이 포트폴리오를 구성하는 방법입니다. 최적 포트폴리오의 구성은 수식을 기반으로 최적화된 해를 찾습니다. 물론 엑셀의 해 찾기와 같은 기능을 사용해 간단한 형태의 최적화 구현이 가능하지만, 방대한 데이터를 다룰 경우에는 속도가 지나치게
Expand Down Expand Up @@ -58,6 +32,11 @@ prices = do.call(cbind,
rets = Return.calculate(prices) %>% na.omit()
```

```{r echo = FALSE}
write.csv(rets, 'data/global_data.sv')
```


`getSymbols()` 함수를 통해 일반적으로 자산배분에서 많이 사용되는 주식과 채권, 대체자산에 해당하는 ETF 가격 데이터를 받은 후 `lapply()``Ad()`, `get()` 함수의 조합을 통해 수정주가만을 선택하고 열의 형태로 묶어줍니다. 그 후 `Return.calculate()` 함수를 통해 수익률을 계산합니다.

```{r message = FALSE, warning = FALSE}
Expand Down
14 changes: 13 additions & 1 deletion 12-backtest.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ chart.TimeSeries(turnover)
2. 포트폴리오를 구성하며, 개별 투자비중은 최소 10%, 최대 30% 제약조건을 설정합니다.
3. 매월 리밸런싱을 실시합니다.

```{r message = FALSE, warning = FALSE}
```{r message = FALSE, warning = FALSE, eval = FALSE}
library(quantmod)
library(PerformanceAnalytics)
library(RiskPortfolios)
Expand All @@ -368,6 +368,18 @@ prices = do.call(cbind, lapply(symbols, function(x) Ad(get(x)))) %>%
rets = Return.calculate(prices) %>% na.omit()
```

```{r echo = FALSE}
library(quantmod)
library(PerformanceAnalytics)
library(RiskPortfolios)
library(tidyr)
library(dplyr)
library(ggplot2)
rets = read.csv('data/data_global.csv', row.names = 1) %>% as.xts()
```


먼저 이전 CHAPTER와 동일하게 글로벌 자산을 대표하는 ETF 데이터를 다운로드한
후 수정주가의 수익률을 계산합니다.

Expand Down
Binary file added Quant-cookbook.rds
Binary file not shown.
20 changes: 20 additions & 0 deletions _bookdown.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,23 @@ output_dir: docs

before_chapter_script: "_common.R"

rmd_files: [
"index.Rmd",
"01-data_programming.Rmd",
"02-information.Rmd",
"03-api.Rmd",
"04-crawling.Rmd",
"05-crawling_practice.Rmd",
"06-crawling_actual.Rmd",
"07-bind_data.Rmd",
"08-data_analysis.Rmd",

"09-factor_basic.Rmd",
"10-factor_adv.Rmd",

"11-portfolio.Rmd",
"12-backtest.Rmd",
"13-evaluation.Rmd",

"14-reference.Rmd"
]
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
26 changes: 25 additions & 1 deletion _common.R
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,28 @@ if(!knitr:::is_html_output()) {

pdf.options(family = "Korea1deb")
options(scipen = 5)
options(digits = 4)
options(digits = 4)

setHook(packageEvent("grDevices", "onLoad"),
function(...){
if(capabilities("aqua"))
grDevices::quartzFonts(
sans =grDevices::quartzFont(rep("AppleGothic",4)),
serif=grDevices::quartzFont(rep("AppleMyungjo",4)))
grDevices::pdf.options(family="Korea1")
grDevices::ps.options(family="Korea1")
}
)
attach(NULL, name = "KoreaEnv")
assign("familyset_hook",
function() {
macfontdevs=c("quartz","quartz_off_screen")
devname=strsplit(names(dev.cur()),":")[[1L]][1]
if (capabilities("aqua") &&
devname %in% macfontdevs)
par(family="sans")
},
pos="KoreaEnv")
setHook("plot.new", get("familyset_hook", pos="KoreaEnv"))
setHook("persp", get("familyset_hook", pos="KoreaEnv"))

Binary file modified data/KOR_fs.Rds
Binary file not shown.
1,002 changes: 500 additions & 502 deletions data/KOR_price.csv

Large diffs are not rendered by default.

Loading

0 comments on commit 6e8fe86

Please sign in to comment.