ledger
is an R package to import data from plain text accounting software like Ledger, HLedger, and Beancount into an R data frame for convenient analysis, plotting, and export.
Right now it supports reading in the register from ledger
, hledger
, and beancount
files.
This package depends on R and the R packages dplyr
, rio
, rlang
, and tidyr
.
To install the development version of the ledger
package (and its R package dependencies) use the install_github
function from the devtools
package in R:
if(!require("devtools")) { install.packages("devtools") } devtools::install_github("trevorld/r-ledger")
This package also has some system dependencies depending on which plaintext accounting files you wish to read to be able to read in:
- ledger
- ledger (>= 3.1) OR for a subset of files hledger (>= 1.4)
- hledger
- hledger (>= 1.4) OR for a subset of files ledger (>= 3.1)
- beancount
To install hledger and beancount run:
$ stack install --resolver=lts hledger-lib-1.9 hledger-1.9 $ pip3 install beancount
Several pre-compiled Ledger binaries are available (often found in several open source repos).
To run the unit tests you'll also need the suggested R package testthat
.
The main function of this package is register
which reads in the register of a plaintext accounting file. This package also exports S3 methods so one can use rio::import
to read in a register and a net_worth
convenience function.
Here is an example reading in the example beancount file generated by bean-example
:
> library("ledger") > example_beancount_file <- tempfile(fileext = ".beancount") > system(paste("bean-example -o", example_beancount_file), ignore.stderr=TRUE) > df <- register(example_beancount_file) > head(df) date mark payee description 1 2016-01-01 * <NA> Opening Balance for checking account 2 2016-01-01 * <NA> Opening Balance for checking account 3 2016-01-01 * <NA> Allowed contributions for one year 4 2016-01-01 * <NA> Allowed contributions for one year 5 2016-01-03 * RiverBank Properties Paying the rent 6 2016-01-03 * RiverBank Properties Paying the rent account amount commodity historical_cost hc_commodity 1 Assets:US:BofA:Checking 4241.86 USD 4241.86 USD 2 Equity:Opening-Balances -4241.86 USD -4241.86 USD 3 Income:US:Federal:PreTax401k -18000.00 IRAUSD -18000.00 IRAUSD 4 Assets:US:Federal:PreTax401k 18000.00 IRAUSD 18000.00 IRAUSD 5 Assets:US:BofA:Checking -2400.00 USD -2400.00 USD 6 Expenses:Home:Rent 2400.00 USD 2400.00 USD market_value mv_commodity 1 4241.86 USD 2 -4241.86 USD 3 -18000.00 IRAUSD 4 18000.00 IRAUSD 5 -2400.00 USD 6 2400.00 USD
Here is an example of using the flags
argument (in this case passed to hledger register
) to filter on any of the tags starting with #trip
in the example beancount file:
> df <- register(example_beancount_file, flags="tag:Tag=#trip") > head(df) date mark payee description account amount commodity 1 2016-09-21 * NA NA Liabilities:US:Chase:Slate -14.84 USD 2 2016-09-21 * NA NA Expenses:Food:Restaurant 14.84 USD 3 2016-09-21 * NA NA Liabilities:US:Chase:Slate -4.81 USD 4 2016-09-21 * NA NA Expenses:Food:Alcohol 4.81 USD 5 2016-09-22 * NA NA Liabilities:US:Chase:Slate -29.22 USD 6 2016-09-22 * NA NA Expenses:Food:Restaurant 29.22 USD historical_cost hc_commodity market_value mv_commodity 1 -14.84 USD -14.84 USD 2 14.84 USD 14.84 USD 3 -4.81 USD -4.81 USD 4 4.81 USD 4.81 USD 5 -29.22 USD -29.22 USD 6 29.22 USD 29.22 USD > suppressPackageStartupMessages(library("dplyr")) > dplyr::filter(df, grepl("Expenses", account)) %>% group_by(account) %>% + summarise(trip_total = sum(amount)) # A tibble: 3 x 2 account trip_total <chr> <dbl> 1 Expenses:Food:Alcohol 46.71 2 Expenses:Food:Coffee 52.00 3 Expenses:Food:Restaurant 1353.95
Note: There is currently a bug in bean-report
that leads us to lose the payee and description for any transactions that uses a #tag
(or ^link
) tag in a beancount file.
If one has loaded in the ledger
package one can also use rio::import
to read in the register:
> df2 <- rio::import(example_beancount_file) > all.equal(df, df2) [1] TRUE
This allows one to use rio::convert
to easily convert plaintext accounting files to other file formats such as a csv file:
$ bean-example -o example.beancount $ Rscript --default-packages=ledger,rio -e 'convert("example.beancount", "example.csv")'
Some examples of using the net_worth
function:
> example_ledger_file <- system.file("extdata", "example.ledger", package = "ledger") > net_worth(example_ledger_file) # A tibble: 1 x 6 date commodity net_worth assets liabilities revalued <date> <chr> <dbl> <dbl> <dbl> <dbl> 1 2018-06-11 USD 8125.39 7646 -520.61 1000 > example_hledger_file <- system.file("extdata", "example.hledger", package = "ledger") > net_worth(example_hledger_file, c("2016-01-01", "2017-01-01", "2018-01-01")) # A tibble: 3 x 5 date commodity net_worth assets liabilities <date> <chr> <dbl> <dbl> <dbl> 1 2016-01-01 USD 5000.00 5000 0.00 2 2017-01-01 USD 4361.39 4882 -520.61 3 2018-01-01 USD 6743.39 7264 -520.61 > example_beancount_file <- tempfile(fileext = ".beancount") > system(paste("bean-example -o", example_beancount_file), ignore.stderr=TRUE) > ledger::net_worth(example_beancount_file) # A tibble: 4 x 5 date commodity net_worth assets liabilities <date> <chr> <dbl> <dbl> <dbl> 1 2018-06-11 IRAUSD 4100.0 4100.0 0.00 2 2018-06-11 USD 104011.7 107221.6 -3209.91 3 2018-06-11 VACHR -128.0 -128.0 0.00 4 2018-06-11 <NA> 0.0 0.0 0.00 > system(paste("bean-report", example_beancount_file, "networth")) Currency Net Worth -------- ---------- USD 104,011.74 -------- ----------
Note: There is currently a bug in hledger register -f file.hledger -o file.csv
where commodities are missing when the amount is zero.