On Sun, Jul 13, 2014 at 7:12 PM, Stefano Zacchiroli <z...@upsilon.cc> wrote:
> On Sun, Jul 13, 2014 at 01:27:30PM -0400, Martin Blais wrote: > > That might even be incorrect, I'm not sure. I believe Ledger does not > > reduce lots, it seems to be matching positive and negative lots by > > "grouping" only at the reporting level (I'm not entirely sure about > > this, Zach make a comment on the doc this morning pointing out the > > --lot-prices and --lot-date options, and the behavior seems to point > > that way, e.g., you can "reduce" a lot that does not exist. I should > > go dig in the source code to find out). So if you have some past > > history of lot additions and So if you have some past history of lot > > additions and reductions, they might affect the average cost you end > > up with using your method, whereas the current inventory may not > > include all the lots that are being used. > > I've already witnessed first hand that Ledger does allow you to reduce > lots that do not exist (going negative). So I'm still not seeing the > risk of incorrect calculation that you hinted at; if you think it's > real, can you try to build one? (or give me some extra hints so that I > can try building it). > Sure. I've attached two Ledger input files which are nearly identical. The first one has two transactions: 2014/06/01 Deposit some cash Equity:OpeningBalances Assets:Investing:Cash $20000 P MSFT $520 2014/07/02 Buy one lot Assets:Investing:Stocks 5 MSFT @ $530 Assets:Investing:Cash 2014/07/02 Buy one lot Assets:Investing:Stocks 5 MSFT @ $540 Assets:Investing:Cash P MSFT $550 If you use your method to calculate the number of shares and the cost basis, you get the correct results: mandarine [default]:~/p/beancount$ ledger -f /home/blais/p/ledger-experiments/avgcost1.lgr --no-color bal Stocks 10 MSFT Assets:Investing:Stocks mandarine [default]:~/p/beancount$ ledger -f /home/blais/p/ledger-experiments/avgcost1.lgr --no-color bal Stocks -B $5350 Assets:Investing:Stocks So the average cost is 5350 $ / 10 MSFT = 535.00 $/MSFT. This is correct. Now add some past history of another transaction in the same commodity, being bought and sold at a different price, so it's gone back to zero by the time we replicate the transactions above: 2014/06/01 Deposit some cash Equity:OpeningBalances Assets:Investing:Cash $20000 2014/06/02 Buy one lot Assets:Investing:Stocks 10 MSFT @ $500 Assets:Investing:Cash 2014/06/03 Sell the lot Assets:Investing:Stocks -10 MSFT @ $510 Assets:Investing:Cash P MSFT $520 2014/07/02 Buy one lot Assets:Investing:Stocks 5 MSFT @ $530 Assets:Investing:Cash 2014/07/02 Buy one lot Assets:Investing:Stocks 5 MSFT @ $540 Assets:Investing:Cash P MSFT $550 Notice that ALL I've done is insert the purchase and sale on 6/2 and 6/3. Everything else is exactly the same. Now try calculating the average cost using your method: mandarine [default]:~/p/beancount$ ledger -f /home/blais/p/ledger-experiments/avgcost2.lgr --no-color bal Stocks 10 MSFT Assets:Investing:Stocks mandarine [default]:~/p/beancount$ ledger -f /home/blais/p/ledger-experiments/avgcost2.lgr --no-color bal Stocks -B $5250 Assets:Investing:Stocks Oops... now the average cost basis is 5250 $/MSFT. A bit of a difference, don't you think? I'm not sure if Martin's patch would affect the outcome. This is a real problem with the way you're computing your cost basis. After my experiments with Ledger, I've come to think its model of calculation is incorrect. Here's what needs to be done to fix it: (1) Inventory booking is not a feature that needs to be carried out at reporting time. Matching inventory lots need to be done only once, with no options, needs to be unambiguous, as part of the processing of the flow of transactions. When a position is reduced, a single and appropriate matching position must be selected. (2) In order to carry this out properly, a distinction needs to be drawn between currency conversions and commodities held at cost, because being able to enforce booking correctly means that you will now force the user to specify cost for all these currency conversion, and your currency conversions would become a pain in the blank to do (nobody cares about the cost basis of price conversions). Of course I'm more than a little biased: this is the model I've implemented in Beancount. A nice side-effect of (1) is that I'm able to output a list of inventory reductions, a list of "trades." I used to have this report in the first version, but have removed it. I'll bring it back shortly after my next release. (Some reporting authorities require you to provide the detail of your trades, so that's a practically useful report to generate.) > > I'm left wondering whether average cost basis should be a per account > > > property, rather than (or maybe: in addition to) something that > > > auto-magically happen the first time you post using "{*}". > > On Sun, Jul 13, 2014 at 01:29:10PM -0400, Martin Blais wrote: > > Actually, there already is one, right here: > > > https://docs.google.com/document/d/1F8IJ_7fMHZ75XFPocMokLxVZczAhrBRBVN9uMhQFCZ4/edit#heading=h.k18hdhviv191 > > Your comments made me realize two things: > > 1) what I actually had in mind was the ability to declare *mandatory* > average cost posting for a given account, inhibiting usage of other > booking methods on it. That was not entirely clear to me when I wrote > my previous message, so thanks for making me realize that :) > > What it is currently supported by your proposal is only setting the > *default* booking method, but that does not stop others methods from > being used. The invariant I've mentioned in the previous post > (ensuring that only one lot exists) can be guaranteed only by > mandatory booking method. > So if you never select a particular lot, how is just using a default different than imposing it? Are you worried about making mistakes and would like to detect it? Or is it that you would prefer the inventory _always_ only include a single lot for that commodity, somehow? If so... why? The cost basis of the aggregation should always sum to the same value, many lots of just-one-lot. >From a software implementation perspective, it's nice to just enforce one lot, but in terms of the calculations, it will make no difference. Leaving the multiple lots to hang around until the next aggregation time _does_ provide the opportunity for a user to book differently. I'm not so sure I understand your concern. Please be specific (this is subtle). If you use {} to specify the cost, e.g., ... -10 MSFT {} this is only unambiguous in the case the inventory has a single lot for that commodity, so that degenerates to the same as the average cost (the average cost of one lot is ... just the cost of that lot). Otherwise, you'd have to use {*} everywhere there might be ambiguity: ... -10 MSFT {*} In which case every lot reduction triggers an aggregation. Besides, after a single aggregation of multiple lots takes place, a user will have little idea of the actual per-unit cost basis, so it's rather unlikely he will specify that oddball cost. [ Aside: upon re-reading the above section, the AVERAGE option is > kinda confusing. My understanding of the FIFO and LIFO options is > that they are limited to disambiguating among the lots that have > been selected by your matching algorithms, i.e., they are not > LIFO/FIFO across all lots. OTOH AVERAGE makes sense only when > computed across all lots. So discussing FIFO/LIFO together with > AVERAGE is puzzling. If that is really what you want, this "detail" > should be communicated more clearly, IMHO. ] > That's an interesting point. From an implementor's point-of-view, it makes all the sense in the world to speak of these together. But from a user's point-of-view, it does raise questions. The question is: Will an average Beancount user be required to understand the inventory booking methods well enough to use them? If so, it would make little difference to discuss it together. I'm not sure. In any case, your bringing it up tells me I need to discuss the subtlety in the final documentation. I'll have to discuss the possibility of merging methods and probably warn against it. > > 2) in terms of design, it'd probably be better to enforce the constraint > of having a single lot as some sort of post-booking check, rather > than overloading even more the expressivity of account declaration > options. (Note: I'm not a Beancounter user, so it's not clear to me > if you've enough expressivity in your checks to encode this. But that > sounds like a better place where to put this.) > Yes, this is a good idea. In general I like to perform checks in separate stages, it makes the code a lot nicer and opens up the possibility to shove this check into a plugin that you could enable only if you want it. An easy way to do this without a syntax extension would be to specify a AVERAGE_ONLY booking type, that would barf if the user attempts to use a non-average method and that might trigger the aggregation on additions as well. I'll update the proposal doc. Thanks a lot for putting some effort in understanding and discussing this long proposal Stefano. -- --- 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 ledger-cli+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
avgcost1.lgr
Description: Binary data
avgcost2.lgr
Description: Binary data