Finstr
:chart_with_upwards_trend: Financial statements in R
Install / Use
/learn @bergant/FinstrREADME

The purpose of finstr package is to create an environment for reproducible financial statement analysis. The package will not cover specific types of analysis (except in examples and package vignettes) but will provide a domain language to write them. With other functions in basic R and existing R packages it anables users to store, share, reuse and reproduce the results of their analitic work.
For now it is offering:
1. Data structure for financial statements
- Reading from data parsed with XBRL package
- Statements in tidy format with accounting taxonomy concepts as columns
- Encapsulates calculation hierarchy of variables
- Default printing in transposed format and with visible hierarchy
2. Statement calculation validation
- Calculation of higher order elements
- Check if calculated values match original values
3. Merge statements
- Merge different periods of equal statement type
- Merge statements of a different type
4. Calculate and reveal
- Custom financial ratio calculations definitions
- Exposing data by rearranging the statament hierarchy
- Time lagged difference
Installation
To install finstr from github use install_github from devtools package:
library(devtools)
install_github("bergant/finstr")
Get data
Use XBRL package to parse XBRL files. For example:
library(XBRL)
# parse XBRL (Apple 10-K report)
xbrl_url2014 <- "https://www.sec.gov/Archives/edgar/data/320193/000119312514383437/aapl-20140927.xml"
xbrl_url2013 <-
"https://www.sec.gov/Archives/edgar/data/320193/000119312513416534/aapl-20130928.xml"
old_o <- options(stringsAsFactors = FALSE)
xbrl_data_aapl2014 <- xbrlDoAll(xbrl_url2014)
xbrl_data_aapl2013 <- xbrlDoAll(xbrl_url2013)
options(old_o)
Prepare statements
With xbrl_get_statements convert XBRL data to statements object.
library(finstr)
st2013 <- xbrl_get_statements(xbrl_data_aapl2013)
st2014 <- xbrl_get_statements(xbrl_data_aapl2014)
st2014
#> Financial statements repository
#> From To Rows Columns
#> StatementOfIncome 2012-09-29 2014-09-27 3 15
#> StatementOfOtherComprehensiveIncome 2012-09-29 2014-09-27 3 14
#> StatementOfFinancialPositionClassified 2013-09-28 2014-09-27 2 33
#> StatementOfCashFlowsIndirect 2012-09-29 2014-09-27 3 33
Statements object is a list of several statement objects (ballance sheets, income and cash flow statements).
To get a single statement use statements object as a regular R list:
balance_sheet2013 <- st2013$StatementOfFinancialPositionClassified
balance_sheet2014 <- st2014$StatementOfFinancialPositionClassified
income2013 <- st2013$StatementOfIncome
income2014 <- st2014$StatementOfIncome
balance_sheet2014
#> Financial statement: 2 observations from 2013-09-28 to 2014-09-27
#> Element 2014-09-27 2013-09-28
#> Assets = 231839 207000
#> + AssetsCurrent = 68531 73286
#> + CashAndCashEquivalentsAtCarryingValue 13844 14259
#> + AvailableForSaleSecuritiesCurrent 11233 26287
#> + AccountsReceivableNetCurrent 17460 13102
#> + InventoryNet 2111 1764
#> + DeferredTaxAssetsNetCurrent 4318 3453
#> + NontradeReceivablesCurrent 9759 7539
#> + OtherAssetsCurrent 9806 6882
#> + AvailableForSaleSecuritiesNoncurrent 130162 106215
#> + PropertyPlantAndEquipmentNet 20624 16597
#> + Goodwill 4616 1577
#> + IntangibleAssetsNetExcludingGoodwill 4142 4179
#> + OtherAssetsNoncurrent 3764 5146
#> LiabilitiesAndStockholdersEquity = 231839 207000
#> + Liabilities = 120292 83451
#> + LiabilitiesCurrent = 63448 43658
#> + AccountsPayableCurrent 30196 22367
#> + AccruedLiabilitiesCurrent 18453 13856
#> + DeferredRevenueCurrent 8491 7435
#> + CommercialPaper 6308 0
#> + DeferredRevenueNoncurrent 3031 2625
#> + LongTermDebt 28987 16960
#> + OtherLiabilitiesNoncurrent 24826 20208
#> + CommitmentsAndContingencies 0 0
#> + StockholdersEquity = 111547 123549
#> + CommonStocksIncludingAdditionalPaidInCapital 23313 19764
#> + RetainedEarningsAccumulatedDeficit 87152 104256
#> + AccumulatedOtherComprehensiveIncomeLossNetOfTax 1082 -471
tail(income2014, 2)
#> Financial statement: 2 observations from 2013-09-28 to 2014-09-27
#> Element 2014-09-27 2013-09-28
#> NetIncomeLoss = 39510 37037
#> + IncomeLossFromContinuingOperationsBefore... = 53483 50155
#> + OperatingIncomeLoss = 52503 48999
#> + GrossProfit = 70537 64304
#> + SalesRevenueNet 182795 170910
#> - CostOfGoodsAndServicesSold 112258 106606
#> - OperatingExpenses = 18034 15305
#> + ResearchAndDevelopmentExpense 6041 4475
#> + SellingGeneralAndAdministrativeExpense 11993 10830
#> + NonoperatingIncomeExpense 980 1156
#> - IncomeTaxExpenseBenefit 13973 13118
Validate statement calculation hierarchy
Recalculate higher order concepts from basic values and check for errors.
check <- check_statement(balance_sheet2014)
check
#> Number of errors: 0
#> Number of elements in errors: 0
In case of error the numbers with errors will be presented along with elements:
check_statement(
within(balance_sheet2014, InventoryNet <- InventoryNet * 2)
)
#> Number of errors: 2
#> Number of elements in errors: 1
#>
#> Element: AssetsCurrent = + CashAndCashEquivalentsAtCarryingValue + AvailableForSaleSecuritiesCurrent + AccountsReceivableNetCurrent + InventoryNet + DeferredTaxAssetsNetCurrent + NontradeReceivablesCurrent + OtherAssetsCurrent
#> date original calculated error
#> 3 2013-09-28 7.3286e+10 7.5050e+10 -1.764e+09
#> 4 2014-09-27 6.8531e+10 7.0642e+10 -2.111e+09
Validation returns all calculation results in a readable data frame. Lets check only operating income from income statement:
check <- check_statement(income2014, element_id = "OperatingIncomeLoss")
check
#> Number of errors: 0
#> Number of elements in errors: 0
check$expression[1]
#> [1] "+ GrossProfit - OperatingExpenses"
check$calculated / 10^6
#> [1] 55241 48999 52503
Merge statements from different periods
Use merge function to create single financial statement data from two statements.
balance_sheet <- merge( balance_sheet2013, balance_sheet2014 )
The structure of merged balance sheets may differ if XBRL taxonomy changes. Function merge takes care of it by expanding the elements hierarchy to fit both statements. The values of any missing elements in different periods is set to 0.
To merge all statements from statements object use merge on statements objects:
# merge all statements
st_all <- merge( st2013, st2014 )
# check if balance sheets are merged:
balance_sheet <- st_all$StatementOfFinancialPositionClassified
balance_sheet$endDate
#> [1] "2012-09-29" "2013-09-28" "2014-09-27"
Merge different types of statements
If there are no matching elements between the two statements merge joins statements by matching their periods. For some financial ratio calculations the combined statement may be
a better starting point.
merge.statement(
st_all$StatementOfFinancialPositionClassified,
st_all$StatementOfIncome )
Calculate financial ratios
Statement object (in our case balance_sheet) is also a data frame object with statement elements as columns and time periods as rows. 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} $$
With dplyr package we can use mutate, select or transmute functions:
library(dplyr)
balance_sheet %>% transmute(
date = endDate,
CurrentRatio = AssetsCurrent / LiabilitiesCurrent
)
#> date CurrentRatio
#> 1 2012-09-29 1.495849
#> 2 2013-09-28 1.678639
#> 3 2014-09-27 1.080113
By using finstr::calculate function we can achieve the same result but don't have to handle the date field and there is a rounding parameter. Lets calculate for example two ratios:
balance_sheet %>% calculate( digits = 2,
Current_Ratio = AssetsCurrent / LiabilitiesCurrent,
Quick_Ratio =
( CashAndCashEquivalentsAtCarryingValue +
AvailableForSaleSecuritiesCurrent +
AccountsReceivableNetCurrent
) / LiabilitiesCurrent
)
#> date Current_Ratio Quick_Ratio
#> 1 201
Related Skills
node-connect
337.7kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
83.3kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
337.7kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
commit-push-pr
83.3kCommit, push, and open a PR
