On Thu, Jun 12, 2014 at 10:27 AM, Martin Michlmayr <[email protected]> wrote:
> * Martin Blais <[email protected]> [2014-06-12 02:05]: > > I don't understand how it works in your example. You're entering > > the positions with price conversion, using the @ sign: > > > > 2014-01-01 Details for shares > > Assets:Investments:Stocks:Share A 15 ShareA @ 20€ > > Assets:Investments:Stocks:Share B 5 ShareB @ 100€ > > Equity:Opening Balance > > > > But his sale is using the "cost" syntax (with {}): > ... > > How does this work under the covers? > > When you specify a cost with @, ledger internally keeps this cost > around. You'll have 15 ShareA {€20}. You can see this with > --lot-prices: > 15 ShareA {€20} Share A > 5 ShareB {€100} Share B > > So when you sell, what you do by saying 5 ShareB {€100} @ €120 is that > you're selling the 5 particular ShareB with a cost of €100. > > Consider you bought 5 ShareB at 100€ and 5 at 110€. Then you'd have: > > 5 ShareB {€100} > 5 ShareB {€110} Share B > > So which one are you selling? You indicate that by using the {..} > syntax. > This is just like Beancount, except that Ledger price conversions are the same as "at-cost conversions." That's what I thought: if I understand correctly, Ledger *always* tracks converted units with their cost, even when they're just price conversions. I think this will cause problems down the road. Beancount treats these two cases differently on purpose; I believe this reflects the semantics of the operation closer and it allows me to solve the multi-currency conversion problem (more detail below about this). > The price/rate is used to balance the transaction but the units are > > deposited in the account without associated cost. This is what you > > would do, for instance, if you were making a withdrawal in a foreign > > country, e.g. in JPY and then spend it locally: you never think of > > these yen in your wallet as "being held at such and such" exchange > > rate, once converted, they have no "cost" to them anymore, all the > > bills are just "yen". > > I think I actually disagree with this particular example. When I get > JPY out of an ATM, I'd say that a very clear exchange rate is attached > to those JPY (because you know exactly how much you paid in your local > currency). > It is true that this is a choice. Let's say you like in the US but you infrequently travel to Europe. You *could* attempt to book all your EUR expenses to lots at a particular cost. In practice, if you had to specify the particular lot each time, this would be a impractical and a major PIA, not even taking into account that that's not how you think about these euros (they're just EUR when you spend them, you never think "oh I'll spend my euros from the first withdrawal because I got a better rate on them". The bills all look the same in your wallet. And they are indeed fungible.). I'll argue that even if you build in an easy way to automatically choose a lot - say you don't specify which lot of your EUR you're spending when you subtract from an account - you really could build in a mechanism that selects a random lot by default, or a specific method, such as FIFO, it's still confusing to do so. What if you have 3 or more currencies? But let's imagine you travel to Japan twice and you still have some > JPY left over from the previous trip. And now you go to the ATM > again. Then you have, let's say: > > 20000 JPY {$0.0090} > 10000 JPY {$0.0098} Assets:Cash > > So now things get complicated. The best solution would probably be to > just calculate the average cost and use that. > The best solution IMHO models how you think about the world. They're just JPY to me. What would do if you have accounts in two countries, in two different currency units, and you make withdrawals in JPY from these two accounts? Now you have "JPY held in USD" and "JPY held in EUR", for instance. Madness. And what happens if you make a conversion in the other direction? I do this all the time: I live in the US but have some remaining non-liquid assets in Canada. For a while I was doing transfers out from CAD to USD, but sometimes, in order to pay a tax liability to the Canadian govt, I might have a cash flow problem, I might have to make some temporary transfers the other way around from USD to CAD in order to make the payment. So now what... I have "USD in CAD" and "CAD in USD"? No way... that's just not how I think about it and that's also not how I want to track it. I suspect most people don't handle this correctly (me included :) > When you use --lot-prices, you actually see what's going on. I > suspect most people do something like this: > > 2014-03-01 * Buy JPY > Assets:Cash 10000 JPY @@ $98 > Assets:Cash > > 2014-03-02 * Spend JPY > Expenses:Foo 10000 JPY > Assets:Cash -10000 JPY > > And now ledger will say: ledger -f ~/e bal ets:cash > $-98 Assets:Cash > > So everything *looks* great. But if you add --lot-prices, you see > that it's a mess: > > $-98 > -10000 JPY > 10000 JPY {$0.0098} Assets:Cash > This is scary confusing to me. Imagine you have a realistic scenario with 10's of transfers in all directions? How can you check that the numbers even make any sense? > > You have -10000 JPY and 10000 JPY {$0.0098}. This is because you > didn't specify the cost. You should have done: > > 2014-03-02 * Spend JPY > Expenses:Foo 10000 JPY {$0.0098} > Assets:Cash -10000 JPY {$0.0098} > > But who does that? > Nobody (I hope). > (In fact, if you're homed in multiple countries and hold assets in > > many places, holding currencies at cost creates incredible > > unnecessary complexities, I'm quite certain this is not what's > > happening). > > Yes, I agree. Unfortunately, this situation applies to me and I > struggle with this all the time. > So I believe I've cracked that problem in my code rewrite last year, and it took me a long, long while to figure out an elegant solution that works without a currency home. My solution - and i'm always open to new ideas for a better one, a better one *may* exist, I'm not claiming that this is the only solution - is to treat the two types of conversions differently. The price conversions (using @) do not attach cost to the units, only conversions at cost, (i.e., using {}). The cost is forgotten in the resulting balance (the transaction still has the price attached to it, of course). The resulting balancing algorithm for a transaction is simple: https://hg.furius.ca/public/beancount/file/0a5f9bba3085/src/python/beancount/core/balance.py#l21 The problem that arises with this solution is that if you sum up the balance of all the transactions, such as you do when you compute balances for a balance sheet, the total amounts does not necessarily balance to zero. Instead, what you'll find is the inverse of the sum of all price conversions. That is, if you convert all of these amounts to a single currency in order to zero them out, the rate at which you would have to do so is the weighted average weight of all the conversion amounts (there's something elegant about that fact actually). So how do I zero out the balance sheet so that it is *precisely* exact? Like everything else in Beancount: I add a transaction. This is an automatically inserted transaction that shows up in the journal, BTW, the user can see it, and it books to Equity:Conversions. I had a design choice to make here: Let's see I have 3 conversion amounts to zero out, in 3 different currencies. I could have (a) chosen one currency as "special" and converted all the other amounts to this currency at some set of rates which makes the whole transaction balance. This has the advantage that it results in a regular-looking transaction, albeit all to Equity accounts. (Note that figuring out the rates to do this is not a trivial problem given the general problem of N currencies to zero out - it admits many solutions - but I think it's possible to come up with one solution using the history of rate conversions and an optimization routine.) Or, (b) refuse to identify any of the legs as "special" and balance all of these legs at a degenerate "0 exchange rate." (B) is a bit ugly, because in a sense it is really just patching up the balance to sum up to zero. "We want it to be zero so let's make it zero." Not super nice, but... this is the one and only place where such a funny kludge appears in the balance calculation, and it holds the advantage that the resulting system truly is currency-agnostic and I don't have to play tricks to find workable rates. I like that better. So I chose solution (b). It's here: https://hg.furius.ca/public/beancount/file/0a5f9bba3085/src/python/beancount/ops/summarize.py#l187 In practice, it has never failed me and does not even cause weirdness. If you draw out a balance sheet, you see two conversion entries: one to account for all the conversions occurring before the beginning of the exercise, and another one to account for the conversions during the period of exercise. I'm even finding these entries useful now, because they report on the sum total of the flow of currencies between all accounts during those periods. The numbers produced are useful. This is a complicated topic. I'd be really interested to hear about other alternatives, perhaps better solutions. -- --- 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.
