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.

Reply via email to