Created
September 2, 2017 22:14
-
-
Save adamnew123456/fd664f121af9f84868f5ca597a606998 to your computer and use it in GitHub Desktop.
Basic analysis of ledger files
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/Rscript | |
printf <- function(fmt, ...) cat(sprintf(fmt, ...)) | |
# Reads a Ledger file by doing CSV export on the CLI, and then slurping | |
# it into R's CSV reader. | |
# | |
# start and end can be used to limit which entries are allowed in by time, | |
# and accounts can be used to limit which accounts are read. | |
ledger.read <- function(filename, | |
start=NA, | |
end=NA, | |
accounts=NULL) { | |
args <- c('-f', filename) | |
if (!is.na(start)) args <- append(args, c('-b', start)) | |
if (!is.na(end)) args <- append(args, c('-e', end)) | |
args <- append(args, c('csv', accounts)) | |
raw <- system2('ledger', args, stdout=TRUE) | |
conn <- textConnection(raw) | |
data <- read.csv( | |
conn, | |
header=FALSE, | |
col.names=c( | |
"date", "tag", "description", "account", "currency", | |
"amount", "X1", "X2"), | |
stringsAsFactors=FALSE) | |
close(conn) | |
data | |
} | |
external <- ledger.read('accounts.ledger') | |
paydate <- NA | |
income <- 0 | |
spent <- 0 | |
transfers <- list() | |
# This is designed to track where the money from each paycheck | |
# ends up, by recording all account credits that occur since | |
# each payday. A couple of assumptions on the structure | |
# of the accounts: | |
# | |
# - All work income is in a subaccount of Income:Work: | |
# - All expenses are in a subaccount of Expenses: | |
# - Virtual transactions (parenthesized) are ignored | |
invisible(apply(external, | |
1, | |
function (txn) { | |
now <<- txn[[1]] | |
account <- txn[[4]] | |
amount <- as.numeric(txn[[6]]) | |
if (grepl('^Income:Work:', account)) { | |
if (!is.na(paydate)) { | |
printf('%s\n', strrep('-', 20)) | |
printf("Between %s And %s\n", paydate, now) | |
printf(" Income: $%f\n", income) | |
printf(" Spent: $%f\n\n", spent) | |
print(t(data.frame(transfers))) | |
printf("\n\n") | |
} | |
income <<- -amount | |
spent <<- 0 | |
transfers <<- list() | |
paydate <<- now | |
} else if (!grepl('^\\(', account)) { | |
if (grepl('^Expenses:', account)) { | |
spent <<- spent + amount | |
} | |
# Not having something like this would show every transaction | |
# twice (credits and debits), including transfers to accounts | |
# which are less interesting like Income | |
if (amount > 0) { | |
if (is.null(transfers[[account]])) { | |
transfers[[account]] <<- 0 | |
} | |
transfers[[account]] <<- transfers[[account]] + amount | |
} | |
} | |
})) | |
if (!is.na(paydate)) { | |
printf('%s\n', strrep('-', 20)) | |
printf("Since %s\n", paydate) | |
printf(" Income: $%f\n", income) | |
printf(" Spent: $%f\n\n", spent) | |
print(t(data.frame(transfers))) | |
printf("\n\n") | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment