Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Only calculate price ratios when company in key_ratios is demoninated in USD and allow specifying the specific exchange #50

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

* Improvements
* Added `pkgdown` integration.
* `tq_get()` where `get = "key.ratios"` now permits specifying a specific exchange - e.g. "EPA:UBI". This enables fetching basic non-US company financials. In the event finances aren't in USD, ratios involving stock price - e.g. "Price to Earnings" - will no be calculated.

* Fixes:
* Require new `quantmod` version 0.4-8 to fix Oanda and Yahoo bugs.
Expand Down
150 changes: 88 additions & 62 deletions R/tq_get.R
Original file line number Diff line number Diff line change
Expand Up @@ -445,20 +445,31 @@ tq_get_util_2 <- function(x, get, complete_cases, map, ...) {

# Convert x to uppercase
x <- stringr::str_to_upper(x) %>%
stringr::str_trim(side = "both") %>%
stringr::str_replace_all("[[:punct:]]", "")
stringr::str_trim(side = "both")

# If the request has a ':', assume that it is in the form of EXCHANGE:SYMBOL
# Allows both forcing a specific exchange source and making requests from non-default exchanges
if ( stringr::str_detect(x,":") ) {
split_req <- stringr::str_split(x,":",2)
stock_exchange <- c(split_req[[1]][1])
x <- split_req[[1]][2]
} else {
# Three Default URLs to try
stock_exchange <- c("XNAS", "XNYS", "XASE") # mornginstar gets from various exchanges
}

# This may need to be less agressive as some symbols have periods
x <- stringr::str_replace_all(x,"[[:punct:]]", "")

tryCatch({

# Download file
stock_exchange <- c("XNAS", "XNYS", "XASE") # mornginstar gets from various exchanges
url_base_1 <- 'http://financials.morningstar.com/finan/ajax/exportKR2CSV.html?&callback=?&t='
url_base_2 <- '&region=usa&culture=en-US&cur=&order=asc'
# Three URLs to try
url <- paste0(url_base_1, stock_exchange, ":", x, url_base_2)

# Try various stock exchanges
for(i in 1:3) {
for(i in 1:length(url)) {
text <- httr::RETRY("GET", url[i], times = 5) %>%
httr::content()

Expand All @@ -477,6 +488,10 @@ tq_get_util_2 <- function(x, get, complete_cases, map, ...) {
}
}

if (is.null(text)) {
stop("Could not fetch key_ratios")
}

# Read lines
text <- text %>%
xml2::as_list() %>%
Expand Down Expand Up @@ -510,7 +525,7 @@ tq_get_util_2 <- function(x, get, complete_cases, map, ...) {
rep("Efficiency", 8)),
group = 1:85
)
} else {
} else if (length(text) == 110) {
# Patch for stocks with 110 lines
skip_rows <- c(1:2, 19:21, 31:32, 41:44, 49, 54, 59, 64:66, 71:73, 94:95, 100:102)

Expand All @@ -534,6 +549,9 @@ tq_get_util_2 <- function(x, get, complete_cases, map, ...) {
rep("Efficiency", 8)),
group = c(1:52, 54:85)
)
} else {
# Catch unknown return from morningstar request
stop("Unexpected return from Morningstar")
}

text <- text[-skip_rows]
Expand All @@ -548,7 +566,6 @@ tq_get_util_2 <- function(x, get, complete_cases, map, ...) {
)
)


# Combine tibble parts into raw data
key_ratios_raw <- dplyr::bind_cols(key_ratios_1, key_ratios_2)

Expand All @@ -567,61 +584,70 @@ tq_get_util_2 <- function(x, get, complete_cases, map, ...) {
dplyr::select(section, sub.section, group, category, date, value)

# Calculate valuations

# Get stock prices
from = lubridate::today() - lubridate::years(12)
valuations_2 <- tq_get(x, get = "stock.prices", from = from) %>%
tq_transmute_xy(adjusted, mutate_fun = to.period, period = "years") %>%
dplyr::mutate(year = lubridate::year(date)) %>%
dplyr::select(year, date, adjusted)

# Get key ratios
valuations_1 <- key_ratios_bind %>%
dplyr::filter(section == "Financials") %>%
dplyr::filter(category %in% c("Revenue USD Mil",
"Shares Mil",
"Earnings Per Share USD",
"Book Value Per Share * USD",
"Operating Cash Flow USD Mil")) %>%
dplyr::mutate(year = lubridate::year(date)) %>%
dplyr::select(year, category, value) %>%
tidyr::spread(key = category, value = value) %>%
dplyr::mutate(`Revenue Per Share USD` = `Revenue USD Mil` / `Shares Mil`,
`Cash Flow Per Share USD` = `Operating Cash Flow USD Mil` / `Shares Mil`) %>%
dplyr::select(year,
`Earnings Per Share USD`,
`Revenue Per Share USD`,
`Book Value Per Share * USD`,
`Cash Flow Per Share USD`)

# Merge and calculate valuations
valuation <- dplyr::left_join(valuations_1, valuations_2, by = "year") %>%
dplyr::mutate(`Price to Earnings` = adjusted / `Earnings Per Share USD`,
`Price to Sales` = adjusted / `Revenue Per Share USD`,
`Price to Book` = adjusted / `Book Value Per Share * USD`,
`Price to Cash Flow` = adjusted / `Cash Flow Per Share USD`) %>%
dplyr::select(date,
`Price to Earnings`,
`Price to Sales`,
`Price to Book`,
`Price to Cash Flow`) %>%
tidyr::gather(key = category, value = value, -date) %>%
dplyr::select(category, date, value) %>%
dplyr::mutate(date = lubridate::as_date(date))

# Get last group number
last_group_num <- key_ratios_bind$group %>% max()

# Create valuation tibble and bind_rows
valuation_bind <- dplyr::bind_cols(
tibble::tibble(section = rep("Valuation Ratios", nrow(valuation))),
tibble::tibble(sub.section = rep("Valuation Ratios", nrow(valuation))),
tibble::tibble(group = rep(seq(last_group_num + 1, length.out = 4), each = 10)),
valuation)

key_ratios <- dplyr::bind_rows(key_ratios_bind, valuation_bind) %>%
dplyr::group_by(section) %>%
tidyr::nest()
currency = strsplit(text[2]," ")[[1]][2]

if (currency == "USD") {
# We can only trust stock price ratios if existing data is in USD
# Get stock prices
from = lubridate::today() - lubridate::years(12)
valuations_2 <- tq_get(x, get = "stock.prices", from = from) %>%
tq_transmute_xy(adjusted, mutate_fun = to.period, period = "years") %>%
dplyr::mutate(year = lubridate::year(date)) %>%
dplyr::select(year, date, adjusted)

# Get key ratios
valuations_1 <- key_ratios_bind %>%
dplyr::filter(section == "Financials") %>%
dplyr::filter(category %in% c("Revenue USD Mil",
"Shares Mil",
"Earnings Per Share USD",
"Book Value Per Share * USD",
"Operating Cash Flow USD Mil")) %>%
dplyr::mutate(year = lubridate::year(date)) %>%
dplyr::select(year, category, value) %>%
tidyr::spread(key = category, value = value) %>%
dplyr::mutate(`Revenue Per Share USD` = `Revenue USD Mil` / `Shares Mil`,
`Cash Flow Per Share USD` = `Operating Cash Flow USD Mil` / `Shares Mil`) %>%
dplyr::select(year,
`Earnings Per Share USD`,
`Revenue Per Share USD`,
`Book Value Per Share * USD`,
`Cash Flow Per Share USD`)

# Merge and calculate valuations
valuation <- dplyr::left_join(valuations_1, valuations_2, by = "year") %>%
dplyr::mutate(`Price to Earnings` = adjusted / `Earnings Per Share USD`,
`Price to Sales` = adjusted / `Revenue Per Share USD`,
`Price to Book` = adjusted / `Book Value Per Share * USD`,
`Price to Cash Flow` = adjusted / `Cash Flow Per Share USD`) %>%
dplyr::select(date,
`Price to Earnings`,
`Price to Sales`,
`Price to Book`,
`Price to Cash Flow`) %>%
tidyr::gather(key = category, value = value, -date) %>%
dplyr::select(category, date, value) %>%
dplyr::mutate(date = lubridate::as_date(date))

# Get last group number
last_group_num <- key_ratios_bind$group %>% max()

# Create valuation tibble and bind_rows
valuation_bind <- dplyr::bind_cols(
tibble::tibble(section = rep("Valuation Ratios", nrow(valuation))),
tibble::tibble(sub.section = rep("Valuation Ratios", nrow(valuation))),
tibble::tibble(group = rep(seq(last_group_num + 1, length.out = 4), each = 10)),
valuation)

key_ratios <- dplyr::bind_rows(key_ratios_bind, valuation_bind) %>%
dplyr::group_by(section) %>%
tidyr::nest()
} else {
# Cant calculate ratios for non-USD companies - just set to return key ratios.
key_ratios <- key_ratios_bind %>%
dplyr::group_by(section) %>%
tidyr::nest()
}

return(key_ratios)

Expand Down