= The problem =
I've just discovered a nasty issue (I'm not sure I'd call it a bug) in the
tree_table renderer, which is the piece of code that accumulates balances
for the Balance Sheet and Income Statement reports. On this line:
https://bitbucket.org/blais/beancount/src/80d30d6896cf5fdcff8c1156cab77107ee8e0f96/beancount/reports/tree_table.py#lines-161
and this line:
https://bitbucket.org/blais/beancount/src/80d30d6896cf5fdcff8c1156cab77107ee8e0f96/beancount/reports/tree_table.py#lines-164
What I do here is iterate through the Positions of the Inventory for the
given account, convert each of the Positions to their cost equivalent and
THEN sum them up. Now, in the normal case of STRICT, FIFO or LIFO booking,
where every reduction matches an actual existing position, this works fine.
However, for "NONE" booking, which is what people use instead of AVERAGE,
which isn't there yet, that may causes surprising results/.
Let's take an example. A possible Inventory resulting from Positions held
at cost, where the reducing positions have their sale cost (which because
the booking method is NONE doesn't have to match any of the other lots)
might look like this if you simply - and perhaps mistakengly - record the
price as the cost basis without care of the inventory contents:
+10 MSFT {89.61 USD, 2018-02-07}
-9 MSFT {96.44 USD, 2018-04-18}
Note here how 96.44 doesn't match any existing lot.
If you first convert to cost and compute the value in cost basis terms, you
get 896.10 + (-867.96) = 28.14.
That's for the one share remaining; clearly wrong ($28 <<< $90/share).
I've noticed this in my retirement account whereby large positions are
being converted from one fund to another due to some instrument name
changes.
The result has been cost basis balances with large negative numbers.
Looks very strange on the balance sheet.
What's happening, if you think about it, is that realized profits are
essentially "merged" with the cost basis.
And the most dramatic realization of this is when there's some profit and a
very large liquidation, resulting in small or no amount of units.
Basically, if you liquidate the whole account, what remains is the
profit/loss...
So if you track those accounts without a rational cost basis, storing the
sale price as the basis, you'll see this situation too.
This is one of the most important reasons the Ledger model of tracking
costs doesn't work.
By providing a cop-out from booking (via "NONE"), this is what I make
possible.
It's a little dangerous.
= The impact, and changes to bean-web to report market-value =
Anyhow, because the accounts on which this "NONE" method is applied are
always non-taxable, the problem has no important impact other than showing
potentially incorrect cost basis sums in the web interface. (I'm not sure
if Fava is affected by this; probably not, I presume they do their own
aggregation.)
To fix the reporting issue, a solution is to instead compute the sum total
of units and report the latest market value instead.
I'm going to change bean-web to do this by default very soon.
(from this branch:
https://bitbucket.org/blais/beancount/src/web_at_market_value/)
It also makes more sense to look at the market value.
And besides, as mentioned in other emails, bean-web's destiny is to get
deleted.
At least in the meantime this issue will be addressed.
= A solution =
I came across this issue again recently when I rebuilt my script to export
all positions to my portfolio tracking spreadsheet.
So this is an annoying recurring thing, really.
(I hope to share how I do portfolio tracking soon, I'd like to write about
this, because I've solved a number of personal portfolio management
problems recently, including intra-day reporting and rerporting of multiple
investment strategies and risk management by using a portfolio of put
options and it's all sourced from Beancount and it's actually simple.)
The Right Thing to do would be to implement the "AVERAGE" booking method.
But that's more work than I can afford the time for right now (I try to
have a life, especially in the summer) and opens up a can of worms.
So I've made a new plugin to let us approximate it instead:
check_average_cost().
What this does is check that when you're adding a reducing posting
(negative number of units) to an account with "NONE" booking method, that
the cost basis of those postings is within a reasonable range of the
average cost basis of the inventory it's being applied to, say, within 1%.
While this doesn't automate accurate matching against existing postings, is
forces you to fan out more of the profit/loss to a P/L account, thereby
largely alleviating the offending numbers.
Here's a simple example:
+5 MSFT {89.61 USD}
+5 MSFT {92.87 USD}
If you try to add a posting of
-2 MSFT {96.44 USD}
to this, you will get an error that says the 96.44 per-unit cost is too far
from the average of $91.24.
It's just an error; it doesn't automate anything.
If you want, you can reduce at the average cost basis and move the imported
"cost" to its rightful place, the price:
-2 MSFT {91.24 USD} @ 96.44 USD
In an ideal world, you'd import reductions like this:
-2 MSFT {} @ 96.44 USD
and let Beancount's "AVERAGE" booking method fill in the number
automatically.
In a large ledger that's been tracked erroneously and with the "NONE"
method - like I did - it would take a good amount of time and typing to fix
all these manually, so perhaps it's not that great a solution. I don't
know. On the other hand, it's an easy check to add as an optional plugin.
Let me know if you find this useful, if anything, partially.
--
You received this message because you are subscribed to the Google Groups
"Beancount" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/beancount/CAK21%2BhOfgje6ncRG6%2BfaFf%3DtL_osfT17%3DWFGqS88%3DzryJX584Q%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.