hledger-interest 1.1 → 1.2
raw patch · 4 files changed
+205/−18 lines, 4 files
Files
- Hledger/Interest.hs +2/−3
- Main.hs +12/−9
- README.md +184/−0
- hledger-interest.cabal +7/−6
Hledger/Interest.hs view
@@ -48,9 +48,8 @@ interestAcc <- asks interestAccount let posts = [ p | p <- tpostings ts, interestAcc == paccount p ] forM_ posts $ \p -> do- bal <- gets (amounts . balance)- let bal' = bal ++ amounts (pamount p)- modify (\st -> st { balance = normaliseMixedAmount (Mixed bal') })+ bal <- gets (balance)+ modify (\st -> st { balance = normaliseMixedAmount (bal + (pamount p)) }) computeInterest :: Day -> Computer () computeInterest day = do
Main.hs view
@@ -29,7 +29,7 @@ { optVerbose = True , optShowVersion = False , optShowHelp = False- , optInput = ""+ , optInput = "-" , optSourceAcc = "" , optTargetAcc = "" , optDCC = Nothing@@ -43,8 +43,8 @@ , Option ['V'] ["version"] (NoArg (\o -> o { optShowVersion = True })) "show version number and exit" , Option ['v'] ["verbose"] (NoArg (\o -> o { optVerbose = True })) "echo input ledger to stdout (default)" , Option ['q'] ["quiet"] (NoArg (\o -> o { optVerbose = False })) "don't echo input ledger to stdout"- , Option [] ["today"] (NoArg (\o -> o { optBalanceToday = True })) "update account until today"- , Option ['f'] ["file"] (ReqArg (\f o -> o { optInput = f }) "FILE") "input ledger file"+ , Option [] ["today"] (NoArg (\o -> o { optBalanceToday = True })) "compute interest up until today"+ , Option ['f'] ["file"] (ReqArg (\f o -> o { optInput = f }) "FILE") "input ledger file (pass '-' for stdin)" , Option ['s'] ["source"] (ReqArg (\a o -> o { optSourceAcc = a }) "ACCOUNT") "interest source account" , Option ['t'] ["target"] (ReqArg (\a o -> o { optTargetAcc = a }) "ACCOUNT") "interest target account" , Option [] ["act"] (NoArg (\o -> o { optDCC = Just diffAct })) "use 'act' day counting convention"@@ -75,16 +75,19 @@ (opts, args) <- getArgs >>= parseOpts when (optShowVersion opts) (putStrLn (display version) >> exitSuccess) when (optShowHelp opts) (putStr usageMessage >> exitSuccess)- when (null (optInput opts)) (commandLineError "required --file option is missing\n") when (null (optSourceAcc opts)) (commandLineError "required --source option is missing\n") when (null (optTargetAcc opts)) (commandLineError "required --target option is missing\n") when (isNothing (optDCC opts)) (commandLineError "no day counting convention specified\n") when (isNothing (optRate opts)) (commandLineError "no interest rate specified\n")- when (length args /= 1) (commandLineError "required argument ACCOUNT is missing\n")+ when (length args < 1) (commandLineError "required argument ACCOUNT is missing\n")+ when (length args > 1) (commandLineError "only one interest ACCOUNT may be specified\n")+ input <- case optInput opts of+ "-" -> getContents+ file -> readFile file+ jnl' <- readJournal Nothing input >>= either fail return let [interestAcc] = args- Right jnl' <- readFile (optInput opts) >>= readJournal Nothing- let jnl = filterJournalTransactionsByAccount [interestAcc] jnl'- ts = sortBy (comparing tdate) (jtxns jnl)+ jnl = filterJournalTransactionsByAccount [interestAcc] jnl'+ ts = sortBy (comparing tdate) (jtxns jnl) cfg = Config { interestAccount = interestAcc , sourceAccount = optSourceAcc opts@@ -98,6 +101,6 @@ | otherwise = return () ts' = runComputer cfg (mapM_ processTransaction ts >> finalize) result- | optVerbose opts = ts ++ ts'+ | optVerbose opts = ts' ++ ts | otherwise = ts' mapM_ (putStr . show) (sortBy (comparing tdate) result)
+ README.md view
@@ -0,0 +1,184 @@+hledger-interest+================++hledger-interest is a small command-line utility based on [Simon+Michael's hleder library](http://hledger.org/). Its purpose is to+compute interest for a given ledger account. Using command line flags,+the program can be configured to use various [day counting+conventions](http://en.wikipedia.org/wiki/Day_count_convention), such as+"act/act", "30/360", "30E/360", and "30/360isda". Furthermore, it+supports several of different interest schemes, i.e. annual interest+with a fixed rate and the scheme mandated by the German law [§ 288 BGB+Verzugszinsen](http://de.wikipedia.org/wiki/Verzugszinssatz). Extending+support for other schemes is fairly easy, but currently requires hacking+the source code.++An overview over the available run-time options can be displayed by+running "`hleder-interest --help`":++ Usage: hledger-interest [OPTION...] ACCOUNT+ -v --verbose echo input ledger to stdout (default)+ -q --quiet don't echo input ledger to stdout+ --today compute interest up until today+ -f FILE --file=FILE input ledger file (pass '-' for stdin)+ -s ACCOUNT --source=ACCOUNT interest source account+ -t ACCOUNT --target=ACCOUNT interest target account+ --act use 'act' day counting convention+ --30-360 use '30/360' day counting convention+ --30E-360 use '30E/360' day counting convention+ --30E-360isda use '30E/360isda' day counting convention+ --constant=RATE constant interest rate+ --annual=RATE annual interest rate+ --bgb288 compute interest according to German BGB288++When run, hledger-interest reads the [ledger+file](http://hledger.org/MANUAL.html#file-format) designated by the+`--file` flag and filters all transactions that change the account+specified on the command line. All other accounts will be ignored. Every+time a transaction modifies the given account's balance -- thereby+changing the amount of money that earns interest --, hledger-interest+transfers the interest that accrued so far. Interest will be debited+from the account designed by the `--source` flag and credited to the+account designed by the `--target` flag.++## Examples++Suppose that you've loaned 1000 Euro from your bank at an annual+interest rate of 5%, and that you would like to see how interest+develops over time. Then you would create a ledger file, say+`loan.ledger`, that looks something like this:++ 2010/09/26 Loan+ Assets:Bank EUR 1000.00+ Liabilities:Loan++Now, `ledger-interest` is run to determine the interest up until today:++ $ hledger-interest -f loan.ledger --act --annual=0.05 --today -s Expenses:Interest -t Liabilities:Loan:Interest Liabilities:Loan+ 2010/09/26 Loan+ Assets:Bank EUR 1000.00+ Liabilities:Loan++ 2010/12/31 5.00% interest for EUR -1000.00 over 96 days+ Liabilities:Loan:Interest EUR -13.15+ Expenses:Interest++ 2011/08/22 5.00% interest for EUR -1000.00 over 234 days+ Liabilities:Loan:Interest EUR -32.05+ Expenses:Interest++Note a separate credit account for the interest was chosen:+`Liabilities:Loan:Interest`. Consequently, interest accrued in one+interest period does *not* earn interest in the following periods. If+interest is credited to the main account instead, that behavior changes:++ $ hledger-interest -f loan.ledger --act --annual=0.05 --today -s Expenses:Interest -t Liabilities:Loan Liabilities:Loan+ 2010/09/26 Loan+ Assets:Bank EUR 1000.00+ Liabilities:Loan++ 2010/12/31 5.00% interest for EUR -1000.00 over 96 days+ Liabilities:Loan EUR -13.15+ Expenses:Interest++ 2011/08/22 5.00% interest for EUR -1013.15 over 234 days+ Liabilities:Loan EUR -32.48+ Expenses:Interest++Of course, loans are supposed to be paid back, and these payments change+the amount of interest accrued. Suppose that `load.ledger` would be+extended by the following transactions:++ 2010/12/11 Payment+ Assets:Bank EUR -150.00+ Liabilities:Loan++ 2011/03/07 Payment+ Assets:Bank EUR -300.00+ Liabilities:Loan++ 2011/08/21 Payment+ Assets:Bank EUR -150.00+ Liabilities:Loan++Then interest would develop as follows:++ $ hledger-interest -f loan.ledger --act --annual=0.05 -s Expenses:Interest -t Liabilities:Loan Liabilities:Loan+ 2010/09/26 Loan+ Assets:Bank EUR 1000.00+ Liabilities:Loan++ 2010/12/11 5.00% interest for EUR -1000.00 over 76 days+ Liabilities:Loan EUR -10.41+ Expenses:Interest++ 2010/12/11 Payment+ Assets:Bank EUR -150.00+ Liabilities:Loan++ 2010/12/31 5.00% interest for EUR -860.41 over 20 days+ Liabilities:Loan EUR -2.36+ Expenses:Interest++ 2011/03/07 5.00% interest for EUR -862.77 over 66 days+ Liabilities:Loan EUR -7.80+ Expenses:Interest++ 2011/03/07 Payment+ Assets:Bank EUR -300.00+ Liabilities:Loan++ 2011/08/21 5.00% interest for EUR -570.57 over 167 days+ Liabilities:Loan EUR -13.05+ Expenses:Interest++ 2011/08/21 Payment+ Assets:Bank EUR -150.00+ Liabilities:Loan++Last but not least, there is a special case known as "Verzugszinsen" in+German law, which applies when someone is supposed to pay a bill, but+fails to do so on time. For every day past the deadline, interest+accrues according to terms specified in [§ 247+BGB](http://www.gesetze-im-internet.de/bgb/__247.html). The command line+flag `--bgb288` enables this scheme in `hledger-interest`.++Let's assume that customer ACME is supposed to pay 35 Euro by+2010/09/15, but the money actually arrives almost half a year late:++ 2010/09/15 Services rendered to Customer ACME+ ACME EUR -35.00 ; 1 hour @ EUR 35.00+ Receivable:ACME++ 2011/03/17 ACME+ ACME EUR 35.00+ Receivable:ACME++According to German law, you are entitled to the following interest:++ $ hledger-interest -f acme.ledger --quiet --bgb288 -s Income:Interest -t Receivable:ACME:Interest Receivable:ACME+ 2010/12/31 5.12% interest for EUR 35.00 over 107 days+ Receivable:ACME:Interest EUR 0.53+ Income:Interest++ 2011/03/17 5.12% interest for EUR 35.00 over 76 days+ Receivable:ACME:Interest EUR 0.37+ Income:Interest++So, if you're smart, then you'll book the payment so that the accrued+interest is paid *first*:++ 2011/03/17 ACME+ ACME EUR 35.00+ Receivable:ACME:Interest EUR -0.90+ Receivable:ACME++This gives the following transaction history for the ACME account:++ $ hledger-interest -f acme.ledger --bgb288 -s Income:Interest -t Receivable:ACME:Interest Receivable:ACME |+ hledger -f - reg Receivable:ACME+ 2010/09/15 Services rendered .. Receivable:ACME EUR 35.00 EUR 35.00+ 2010/12/31 5.12% interest for.. Re:ACME:Interest EUR 0.53 EUR 35.53+ 2011/03/17 5.12% interest for.. Re:ACME:Interest EUR 0.37 EUR 35.90+ 2011/03/17 ACME Re:ACME:Interest EUR -0.90 EUR 35.00+ Receivable:ACME EUR -34.10 EUR 0.90
hledger-interest.cabal view
@@ -1,5 +1,5 @@ Name: hledger-interest-Version: 1.1+Version: 1.2 Synopsis: computes interest for a given account License: BSD3 License-file: LICENSE@@ -9,17 +9,18 @@ Category: Finance Build-type: Simple Cabal-version: >= 1.6-Tested-With: GHC == 6.12.3, GHC == 7.0.4, GHC == 7.2.1+Tested-with: GHC == 6.12.3, GHC == 7.0.4, GHC == 7.2.1+Data-files: README.md Description: hledger-interest is a small command-line utility based on Simon Michael's hleder library. Its purpose is to compute interest for a given ledger account. Using command line flags, the program can be- configured to use various schemes for day-counting, such as act/act,- 30/360, 30E/360, and 30/360isda. Furthermore, it supports a (small)+ configured to use various schemes for day-counting, such as act\/act,+ 30\/360, 30E\/360, and 30\/360isda. Furthermore, it supports a (small) number of interest schemes, i.e. annual interest with a fixed rate and the scheme mandated by the German BGB288 (Basiszins für Verbrauchergeschäfte). Extending support for other schemes is fairly- easy, but currently requires changing to the source code.+ easy, but currently requires changes to the source code. . As an example, consider the following loan, stored in a file called @test.ledger@:@@ -111,7 +112,7 @@ Executable hledger-interest Main-is: Main.hs- Build-depends: base >= 3 && < 5, hledger-lib >= 0.14, time, mtl, Cabal+ Build-depends: base >= 3 && < 5, hledger-lib == 0.14, time, mtl, Cabal other-modules: Hledger.Interest Hledger.Interest.DayCountConvention Hledger.Interest.Rate