Sorry to bring up an old topic. I followed this with some interest back when we
discussed it, but my own thoughts hadn't yet crystalized, so I was silent. Now
I have thoughts to share.
Martin Blais:
> I think the question should be phrased in terms of what precision you want to
> represent numbers _internally_. Isn't a worthy goal to attempt to replicate
> the same precision as the real-world accounts they represent?
I agree. To me, display precision is much less important than the internal
representation.
Martin again:
> Rounding should occur at the point of calculating the "balance amount", that
> is, the amount that is used to balance against the rest of the postings of
> the transaction.
I agree again, but disagree with how this is implemented in both ledger and
beancount (I am not familiar with hledger). In particular, I think that the
only way to avoid strange situations is for every transaction to balance
exactly, as in A+B=0 to the full precision of the internal representation.
Let's ignore the concept of elided values and start by thinking only about the
whether a transaction balances.
There are two cases.
Case 1: Single currency. Postings should balance exactly.
2014-01-01 * transfer
Assets:Bank1 $1.00
Assets:Bank2 $-1.001
It seems pretty obvious that this should trigger an error. Ledger gets this
right because it requires all transactions to balance to the maximum precision
specified in the document (not quite, we'll get to this later). Beancount, with
its fixed tolerance, lets this through (Even $-1.01 would pass). Even if the
tolerance is exposed as an option, you give the user the opportunity to screw
things up.
Case 2: Multiple currencies.
2014-01-01 * buy AAA
Assets:Investments 2 AAA @ 10.1234 EUR
Assets:Bank -20.25 EUR
The 2 AAA and the -20.25 EUR are actual amounts. The quoted rate may have been
10.1234, but the truth is, you bought at 10.125 EUR (sucker!)
Note that this need to adjust price due to rounding does not arise solely from
overprecise pricing, but also when you purchase fractional shares.
2014-01-01 * buy VPMCX
Assets:Investments 9.66 VPMCX @ 103.52 USD
Assets:Bank 1000.00 USD
Again, the $1000 and the 9.66 shares are exact quantities. They do not
represent something that has been rounded. You do not have an extra, invisible
0.0032 USD lying around. It is the $103.52 that is wrong.
So one solution is to simply record the share price you paid instead of the
share price you were quoted. This is the same as Martin Machlmayr's suggestion
to use '@@' instead of '@'. But as Martin also pointed out, there is value in
using '@', namely, your cost basis can match the bank's report, the pricedb
gets an accurate market price, and you get an extra check that you haven't
mistyped a number.
A different solution is for the program to replace the cost basis that you
specify with the true cost, as long as it is close enough. But this doesn't
solve the problem that you might want to attach the bank-reported cost to the
posting, or see it in reports.
One final solution, and what I have settled on for now, is a rounding account.
I insert one manually (with elided amount), but the program could easily do
this for you. It sweeps away whatever is left over, and has accumulated 0.12
USD (in expenses) for me so far this year. The alternative is that my
double-entry accounting ledger is out of balance by 12 cents per year. (Maybe
not a big deal, but it bugs me.)
The point is, no matter how you decide to round the amounts, you have to
account for the rounding in some way or accept the fact that your system is out
of balance.
Note that either of these automated solutions could probably be implemented
using beancount plugins.
Weird things happening
If you don't require each transaction to balance, you easily drift away from
overall balance. In Ledger:
D 1.00 USD
2014-01-01 Test
assets 1 CAD @ 1.005 USD
liabilities
2014-01-02 Test
assets 1 CAD @ 1.005 USD
liabilities
% ledger bal liabilities
2014-01-01 Test liabilities -1.00 USD -1.00 USD
2014-01-02 Test liabilities -1.00 USD -2.01 USD
Here is another:
2014-01-01 Test
assets 1 CAD @ 1.005 USD
liabilities -1.00 USD
2014-01-02 Test
assets 1 CAD @ 1.005 USD
liabilities -1.00 USD
2014-01-03 Test
assets 1 CAD @ 1.005 USD
liabilities -1.005 USD
% ledger bal -B
3.015 USD assets
-3.005 USD liabilities
--------------------
0.010 USD
This second example is curious because if you put the third transaction at the
beginning, the other two now fail to balance, because the precision becomes 3
decimal points before they are read, whereas before the precision switched from
2 to 3 partway through.
Eliding postings
Once you have what it means to balance figured out, it is easy to complete a
transaction with an elided posting. Simply choose the value that minimizes the
error. (And then either roll the error into an adjusted price or add a rounding
transaction.) Obviously, to do this, you would need rules about precision, per
currency and possibly per account. If you really want to, you can have custom
rounding rules.
In my experience, though, you will often still get the number wrong, because at
the end of the day, the bank will do what it does for its own reasons. (In my
401k, for example, I contribute a fixed $X to buy Y fractional shares at price
Z, but X - Y*Z has been as big as 2.5 cents because strictly speaking the bank
is setting Y = round(X/Z, 3), even though I would never think of it that way,
or record it that way in my ledger.)
Nathan
--
---
You received this message because you are subscribed to the Google Groups
"Ledger" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.