From 48d133a2aae8579d82d6dd4f4c2b2a8e52f10f93 Mon Sep 17 00:00:00 2001 From: Bergant <darko.bergant@adacta.si> Date: Sat, 28 Mar 2015 14:19:41 +0100 Subject: [PATCH] calculate calculate --- DESCRIPTION | 3 +- NAMESPACE | 4 +- R/finstr.R | 131 ++++++++--------------------------- man/calculate.Rd | 32 +++++++++ man/expose.Rd | 54 --------------- man/finstr-package.Rd | 14 ++-- man/get_elements.Rd | 2 +- man/grapes-without-grapes.Rd | 18 ----- man/other.Rd | 16 ----- man/xbrl_create_data.Rd | 1 + vignettes/Overview.Rmd | 43 +++++++++--- 11 files changed, 104 insertions(+), 214 deletions(-) create mode 100644 man/calculate.Rd delete mode 100644 man/expose.Rd delete mode 100644 man/grapes-without-grapes.Rd delete mode 100644 man/other.Rd diff --git a/DESCRIPTION b/DESCRIPTION index 9100be3..3190962 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -14,7 +14,8 @@ Imports: dplyr, tidyr, XBRL, - RCurl + RCurl, + lazyeval Suggests: testthat, knitr VignetteBuilder: knitr diff --git a/NAMESPACE b/NAMESPACE index 97e0306..87b0340 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -6,11 +6,9 @@ S3method(print,elements) S3method(print,statement) S3method(print,statements) S3method(print,xbrl_vars) -export("%without%") -export(expose) +export(calculate) export(get_elements) export(get_elements_hierarchy) -export(other) export(xbrl_get_relations) export(xbrl_get_statement_ids) export(xbrl_get_statements) diff --git a/R/finstr.R b/R/finstr.R index 47c385e..ee61e9f 100644 --- a/R/finstr.R +++ b/R/finstr.R @@ -22,6 +22,7 @@ NULL #' Function to create package data included in the package #' #' @details xbrlDoAll creates > 5Mb list - we need only 2Mb +#' @keywords internal xbrl_create_data <-function() { file1 <- "http://edgar.sec.gov/Archives/edgar/data/320193/000119312513416534/aapl-20130928.xml" @@ -358,7 +359,7 @@ xbrl_get_statements <- function(xbrl_vars, rm_prefix = "us-gaap_") { #' @param x A statement object #' @param parent_id used as filter if defined #' @param all if FALSE only terminal elements from the hierarchy will be returned -#' @seealso \code{\link{get_elements}} and \code{\link{expose}} +#' @seealso \code{\link{calculate}} #' @export get_elements <- function(x, parent_id = NULL, all = TRUE) { # returns all terminating elements @@ -396,108 +397,6 @@ as.elements <- function(x) { return(x) } -#' Calculate higher order element values -#' -#' @param x a statement object -#' @param ... elements of the statement -#' @return a statement object -#' @description Generate statement with agregated values. -#' @details expose uses calculation link base hierarchy to find -#' which concept to include in the aggregate. The aggregation function is -#' always \emph{sum}. See examples for more details. -#' @examples -#' \dontrun{ -#' -#' # total assets -#' st1$StatementOfFinancialPositionClassified %>% -#' expose( -#' "Assets" -#' ) -#' -#' # current and non-current assets (using other) -#' st1$StatementOfFinancialPositionClassified %>% -#' expose( -#' CurrentAssets = "AssetsCurrent", -#' NoncurrentAssets = other("Assets"), -#' "LiabilitiesAndStockholdersEquity" -#' ) -#' -#' # calculate non-current assets (using %without% operator) -#' st1$StatementOfFinancialPositionClassified %>% -#' expose( -#' NoncurrentAssets = "Assets" %without% "AssetsCurrent", -#' CurrentAssets = "AssetsCurrent", -#' "LiabilitiesAndStockholdersEquity" -#' ) -#' } -#' -#' @seealso \link{finstr} -#' @export -expose <- function(x, ...) { - stop("Under construction") - elements <- list(...) - # prepare for "other" and "without" directive - used_cols <- c() - for(i in seq_along(elements)) { - cols <- get_elements(x, elements[[i]]) - if(elements[[i]][1] == "") - cols <- get_elements(x) - el_type <- attr(elements[[i]], "type") - if( !is.null(el_type) && el_type == "other") { - cols <- cols[ !cols %in% used_cols] - elements[[i]] <- cols - } - if( !is.null(el_type) && el_type == "without") { - e1 <- get_elements(x, elements[[i]][[1]]) - e2 <- get_elements(x, elements[[i]][[2]]) - cols <- e1[!e1 %in% e2] - elements[[i]] <- cols - } - used_cols <- union(used_cols, cols) - } - - res <- - data.frame( - do.call( - cbind, - lapply(elements, function(element) { - cols <- get_elements(x, element) - cbind(rowSums(x[cols])) - }) - ) - ) - names(res) <- elements - names(res)[names(elements)!=""] <- names(elements)[names(elements)!=""] - res <- cbind(x[,1:4], res ) - class(res) <- c("statement", "data.frame") - return(res) -} - -#' Used in expose to sum the concepts not already used -#' -#' @param element element from concept hierarchy -#' @keywords internal -#' @export -other <- function(element = NULL) { - if(missing(element)){ - element <- "" - } - attr(element, "type") <- "other" - return(element) -} - -#' Used in expose to sum the concepts under e1 without e2 -#' -#' @param e1 element group -#' @param e2 element group not to be included -#' @keywords internal -#' @export -'%without%' <- function(e1, e2) { - x <- list(e1, e2) - attr(x, "type") <- "without" - return(x) -} - #' Merge two financial statements #' #' @description Merge two statements from different time periods. @@ -577,4 +476,30 @@ merge.statements <- function(x, y, ...) { return(z) } +#' Calculate formulas +#' +#' @param x a statement object +#' @param ... list of formulas +#' @examples +#' \dontrun{ +#' +#' balance_sheet %>% calculate( +#' +#' current_ratio = AssetsCurrent / LiabilitiesCurrent, +#' +#' quick_ratio = +#' ( CashAndCashEquivalentsAtCarryingValue + +#' AvailableForSaleSecuritiesCurrent + +#' AccountsReceivableNetCurrent +#' ) / LiabilitiesCurrent +#' ) +#' } +#' @export +calculate <- function(x, ...) { + + #dplyr::transmute_(x, endDate = ~endDate, .dots = lazyeval::lazy_dots(...)) + dplyr::transmute_(x, endDate = ~endDate, .dots = lazyeval::lazy_dots(...)) %>% + dplyr::select(everything(), -matches("^\\.")) + +} diff --git a/man/calculate.Rd b/man/calculate.Rd new file mode 100644 index 0000000..0273b19 --- /dev/null +++ b/man/calculate.Rd @@ -0,0 +1,32 @@ +% Generated by roxygen2 (4.1.0): do not edit by hand +% Please edit documentation in R/finstr.R +\name{calculate} +\alias{calculate} +\title{Calculate formulas} +\usage{ +calculate(x, ...) +} +\arguments{ +\item{x}{a statement object} + +\item{...}{list of formulas} +} +\description{ +Calculate formulas +} +\examples{ +\dontrun{ + +balance_sheet \%>\% calculate( + + current_ratio = AssetsCurrent / LiabilitiesCurrent, + + quick_ratio = + ( CashAndCashEquivalentsAtCarryingValue + + AvailableForSaleSecuritiesCurrent + + AccountsReceivableNetCurrent + ) / LiabilitiesCurrent +) +} +} + diff --git a/man/expose.Rd b/man/expose.Rd deleted file mode 100644 index 8e85c54..0000000 --- a/man/expose.Rd +++ /dev/null @@ -1,54 +0,0 @@ -% Generated by roxygen2 (4.1.0): do not edit by hand -% Please edit documentation in R/finstr.R -\name{expose} -\alias{expose} -\title{Calculate higher order element values} -\usage{ -expose(x, ...) -} -\arguments{ -\item{x}{a statement object} - -\item{...}{elements of the statement} -} -\value{ -a statement object -} -\description{ -Generate statement with agregated values. -} -\details{ -expose uses calculation link base hierarchy to find -which concept to include in the aggregate. The aggregation function is -always \emph{sum}. See examples for more details. -} -\examples{ -\dontrun{ - -# total assets -st1$StatementOfFinancialPositionClassified \%>\% - expose( - "Assets" - ) - -# current and non-current assets (using other) -st1$StatementOfFinancialPositionClassified \%>\% - expose( - CurrentAssets = "AssetsCurrent", - NoncurrentAssets = other("Assets"), - "LiabilitiesAndStockholdersEquity" - ) - -# calculate non-current assets (using \%without\% operator) -st1$StatementOfFinancialPositionClassified \%>\% - expose( - NoncurrentAssets = "Assets" \%without\% "AssetsCurrent", - CurrentAssets = "AssetsCurrent", - "LiabilitiesAndStockholdersEquity" - ) -} -} -\seealso{ -\link{finstr} -} - diff --git a/man/finstr-package.Rd b/man/finstr-package.Rd index d9e5a99..f0bb977 100644 --- a/man/finstr-package.Rd +++ b/man/finstr-package.Rd @@ -22,9 +22,8 @@ manipulate financial statements data in R. \itemize{ \item Convert XBRL (XML files and schemas) to a list of data frames - (facts, contexts, roles and hierarchies) with \code{\link{xbrl_parse_min}} - function. It is using XBRL parsing primitives from \link[XBRL]{XBRL-package} - to parse only minimum data needed to construct financial statements. + (facts, contexts, roles and hierarchies) with \link[XBRL]{xbrlDoAll} + function from \link[XBRL]{XBRL-package}. \item Function \code{\link{xbrl_get_statements}} converts the XBRL data list to \emph{statements} object. It is a list of @@ -43,10 +42,11 @@ manipulate financial statements data in R. } \section{Using Financial Statements Data}{ \itemize{ -\item To calculate values of higher order concepts and concept - combinations (e.g. \emph{non-current assets}) use \code{\link{expose}} function. - The result of expose function is a statement object with transformed concepts - (data frame columns). +\item To calculate values with formulas use + use \code{\link{calculate}} function or use + statement as a data frame with R base functions or packages + like \link[dplyr]{dplyr} for manipulating data + frames. \item Function \code{\link{merge.statement}} can merge statements from different periods to a single statement. The elements and hierarchies are merged to diff --git a/man/get_elements.Rd b/man/get_elements.Rd index c5db7e7..2b615bb 100644 --- a/man/get_elements.Rd +++ b/man/get_elements.Rd @@ -17,6 +17,6 @@ get_elements(x, parent_id = NULL, all = TRUE) Get the terminating nodes of the calculation hierarchy } \seealso{ -\code{\link{get_elements}} and \code{\link{expose}} +\code{\link{calculate}} } diff --git a/man/grapes-without-grapes.Rd b/man/grapes-without-grapes.Rd deleted file mode 100644 index 32ce8af..0000000 --- a/man/grapes-without-grapes.Rd +++ /dev/null @@ -1,18 +0,0 @@ -% Generated by roxygen2 (4.1.0): do not edit by hand -% Please edit documentation in R/finstr.R -\name{\%without\%} -\alias{\%without\%} -\title{Used in expose to sum the concepts under e1 without e2} -\usage{ -e1 \%without\% e2 -} -\arguments{ -\item{e1}{element group} - -\item{e2}{element group not to be included} -} -\description{ -Used in expose to sum the concepts under e1 without e2 -} -\keyword{internal} - diff --git a/man/other.Rd b/man/other.Rd deleted file mode 100644 index c83e10d..0000000 --- a/man/other.Rd +++ /dev/null @@ -1,16 +0,0 @@ -% Generated by roxygen2 (4.1.0): do not edit by hand -% Please edit documentation in R/finstr.R -\name{other} -\alias{other} -\title{Used in expose to sum the concepts not already used} -\usage{ -other(element = NULL) -} -\arguments{ -\item{element}{element from concept hierarchy} -} -\description{ -Used in expose to sum the concepts not already used -} -\keyword{internal} - diff --git a/man/xbrl_create_data.Rd b/man/xbrl_create_data.Rd index e1509bd..1ed6b1d 100644 --- a/man/xbrl_create_data.Rd +++ b/man/xbrl_create_data.Rd @@ -12,4 +12,5 @@ Function to create package data included in the package \details{ xbrlDoAll creates > 5Mb list - we need only 2Mb } +\keyword{internal} diff --git a/vignettes/Overview.Rmd b/vignettes/Overview.Rmd index 300155b..bea4d6b 100644 --- a/vignettes/Overview.Rmd +++ b/vignettes/Overview.Rmd @@ -108,13 +108,13 @@ balance_sheet <- st_all$StatementOfFinancialPositionClassified ## Calculate new values and ratios Statement object (in our case `balance_sheet`) is also a data frame object. With elements (or concepts) as columns and time periods as rows. -It is possible then to use statement as a data frame: +It is possible then to use statement as a data frame. Lets calculate current ratio which is defined by $$ Current Ratio = \frac{Current Assets}{Current Liabilities} $$ -```{r current_ratio, eval=FALSE} +```{r dplyr} library(dplyr) balance_sheet %>% @@ -123,11 +123,31 @@ balance_sheet %>% ``` +By using `calculate` function we can achieve the same result with +less verbose language. Lets calculate now two ratios: + +```{r calculate} +library(dplyr) + +balance_sheet %>% calculate( + + Current_Ratio = AssetsCurrent / LiabilitiesCurrent, + + Quick_Ratio = + ( CashAndCashEquivalentsAtCarryingValue + + AvailableForSaleSecuritiesCurrent + + AccountsReceivableNetCurrent + ) / LiabilitiesCurrent + +) +``` + + If we need a period average value we can use a `lag` function. For example, to calculate *DSO* (days sales outstanding) over longer periods the average of account receivable is compared to net sales. -We will use the formula for yearly statements: +We will use the formula for yearly preiods: $$ DSO = \frac{Average Accounts Receivable}{Sales Revenue} \times 365 $$ @@ -135,16 +155,17 @@ In this case we need to connect two type of statements: balance sheets and income statements. With matching reporting periods it can be accomplished with joining two data frames: -```{r DaysSalesOutstanding, eval=FALSE} +```{r DaysSalesOutstanding} balance_sheet %>% inner_join( st_all$StatementOfIncome, by = "endDate") %>% - mutate( - AccountReceivableLast = lag(AccountsReceivableNetCurrent), - AccountReceivableAvg = (AccountReceivableLast+AccountsReceivableNetCurrent)/2, - DaysSalesOutstanding = AccountReceivableAvg / SalesRevenueNet * 365 - ) %>% - select(endDate, DaysSalesOutstanding) %>% - na.omit() + calculate( + .AccountReceivableLast = lag(AccountsReceivableNetCurrent), + .AccountReceivableAvg = (.AccountReceivableLast + AccountsReceivableNetCurrent)/2, + DaysSalesOutstanding = .AccountReceivableAvg / SalesRevenueNet * 365 + ) ``` + +The leading dot instructs the calculate function to hide the value. In our case +only DaysSalesOutstanding is selected in final result. -- GitLab