Say I'm a US entity with USD as my reporting currency, but I order
widgets from a Japanese supplier and receive an invoice in JPY; later
I pay via wire transfer at a bank that does the JPY/USD exchange for
me.  How can I correctly report the cost of the widgets separately
from the foreign currency exchange loss/gain?

For example, here's a ledger, from the above information sources:

2019-01-02 Opening Balances
    Assets:Bank                              4000.00 USD
    Equity:Opening Balances

2019-02-01 Acme Widgets, Inc.
    Expenses:Widgets                            1000 JPY
    Liabilities:Payable

2019-10-01 Acme Widgets, Inc.
    Liabilities:Payable                         1000 JPY @@ 9.75 USD
    Assets:Bank

Separately, I consult an exchange like openexchangerates.org for the
exchange rates over time, and I get a price database[*]:

P 2019-01-01 23:59:58 JPY 0.009118097600116712 USD
P 2019-08-25 23:59:59 JPY 0.009537502652617925 USD

This is enough information to report expenses in USD according to US
GAAP as prescribed in ASC 830:

 - At the time of the expense, 1000 JPY = 9.12 USD, so the expense
   report should say

      Expenses:Widgets  9.12 USD

 - At the time of the payment, 1000 JPY = 9.53 USD, and I had to pay
   the bank 9.75 USD.  So I lost 0.41 USD owing to the change in
   exchange rate, and had to pay 0.22 USD overhead for the exchange,
   for a total of 0.63 USD in foreign currency exchange expenses:

      Expenses:Currency exchange  0.63 USD

   (Perhaps I might even want to report the currenty exchange loss
   separately from the overhead of my bank's exchange, but I'll be
   happy for today even if I can't make that distinction.)

So I would like to see the following report:

   % ledger <MAGIC OPTIONS HERE> balance
            3990.25 USD  Assets:Bank
           -4000.00 USD  Equity:Opening Balances
               9.75 USD  Expenses
               0.63 USD    Currency exchange
               9.12 USD    Widgets
   --------------------
                      0

How can I get this?  (Finding a way to patch ledger and submitting it
upstream is an acceptable answer if it's not actually feasible in
ledger today -- guidance on the relevant logic would be appreciated!)


Here are some approaches I tried:

1. Run `ledger --exchange USD balance' or `ledger --market balance'.
   But these give:

            3990.25 USD  Assets:Bank
           -4000.00 USD  Equity:Opening Balances
               9.75 USD  Expenses:Widgets
   --------------------
                      0

   That is, they fail to distinguish the cost of the widget from the
   cost of waiting a few months to make the payment or the cost
   imposed by the bank on exchanging currencies.

2. Run `ledger --historical balance'.  But this gives:

            3990.25 USD  Assets:Bank
           -4000.00 USD  Equity:Opening Balances
               9.12 USD  Expenses:Widgets
               0.63 USD  Liabilities:Payable
   --------------------
                      0

   That is, although it correctly splits the widget and exchange
   costs, it leaves the exchange cost in  Liabilities:Payable  rather
   than in an expense account.

   In this simplified example perhaps I could just move everything
   left in  Liabilities:Payable  to  Expenses:Currency exchange, but
   in the actual ledger there's one or two separate liability accounts
   per invoice, so that's not practical.

   Further, --historical will do the wrong thing if I hold any JPY
   monetary assets and want to know their current value in USD.  In
   particular, while --historical is appropriate for displaying
   expenses and income, and perhaps for displaying nonmonetary assets,
   it is wrong for displaying monetary assets and liabilities.

3. Use the VALUE tag to specify different valuation rules for
   different accounts, as recommended by the manual in the section
   `Commodity pricing'.  This appears to be broken, and there are
   essentially no automatic tests for it, which makes me wonder
   whether it ever worked and has ever been used in practice.

   The manual says that everything works by default as if there were a
   global automated transaction

   = expr true
       ; VALUE:: market(amount, date, exchange)

   but if I add this explicitly, amounts that arise from exchanges
   become wildly unreasonable:

   % ledger -X USD balance
            3990.25 USD  Assets:Bank
           -4000.00 USD  Equity:Opening Balances
            9120.00 USD  Expenses:Widgets
           18870.00 USD  Liabilities:Payable
   --------------------
           27980.25 USD

   It seems that there is a spurious multiplication; things look more
   reasonable if I also divide by amount,

   = expr true
       ; VALUE:: market(amount, date, exchange)/amount

   then I get:

   % ledger -X USD balance
            3990.25 USD  Assets:Bank
           -4000.00 USD  Equity:Opening Balances
              10.00 USD  Expenses:Widgets
   --------------------
               0.25 USD

   The numbers are still unreasonable, though, because apparently
   something got rounded far too much on the way.  If I explicitly
   unround, as in

   = expr true
       ; VALUE:: unrounded(market(unrounded(amount), date, exchange)/amount)

   then it looks somewhat more reasonable:

   % ledger -X USD balance
       3990.2500000 USD  Assets:Bank
      -4000.0000000 USD  Equity:Opening Balances
          9.1181000 USD  Expenses:Widgets
          0.6319000 USD  Liabilities:Payable
   --------------------
                      0

   There seems to be a little more precision if I unround and use
   `commodity' rather than `amount' -- not sure why:

   = expr true
       ; VALUE:: unrounded(market(commodity, date, exchange))

   % ledger -X USD balance
   3990.250000000000000000 USD  Assets:Bank
   -4000.000000000000000000 USD  Equity:Opening Balances
   9.118097600116712000 USD  Expenses:Widgets
   0.631902399883288000 USD  Liabilities:Payable
   --------------------
                      0

   But again the amount went into  Liabilities:Payable  rather than
   into  Expenses:Currency exchange.

   So, although I can set the valuation function differently for
   different account subtrees in order to value expenses and income at
   the historical rate yet value assets and liabilities at today's
   rate, as in

   = /^Equity:/ or /^Expenses:/ or /^Income:/
       ; Value:: unrounded(market(commodity, post.date, exchange))
   = /^Assets:/ or /^Liabilities:/
       ; Value:: unrounded(market(commodity, date, exchange))

   it still doesn't help to report foreign exchange expenses.

4. Manually edit the transactions to add explicit lot prices based on
   the exchange rate from the price database, _and_ add an explicit
   Expenses:Currency  exchange account posting:

   2019-01-02 Opening Balances
       Assets:Bank        4000.00 USD
       Equity:Opening Balances

   2019-02-01 Acme Widgets, Inc.
       Expenses:Widgets      1000 JPY {=0.009118097600116712 USD}
       Liabilities:Payable

   2019-10-01 Acme Widgets, Inc.
       Liabilities:Payable   1000 JPY {=0.009118097600116712 USD} @@ 9.75 USD
       Assets:Bank          -9.75 USD
       Expenses:Currency exchange

   This does give the report I want:

   % ledger -f /tmp/riastradh/test.ledger -X USD balance
            3990.25 USD  Assets:Bank
           -4000.00 USD  Equity:Opening Balances
               9.75 USD  Expenses
               0.63 USD    Currency exchange
               9.12 USD    Widgets
   --------------------
                      0

   However, this is not an option for several reasons:

   (a) every exchange rate tag {=0.009118097600116712 USD} has to be
       correct for the date, opening a large amount of data entry
       error;

   (b) many of the lots pass through several intermediate accounts in
       separate transactions imported automatically from statements:
       i. PayPal currency conversion from Assets:PayPal to Assets:PayPal
      ii. PayPal payment from Assets:PayPal to Liabilities:PayPal:<txid>
     iii. invoice payment from Liabilities:PayPal:<txid> to
          Liabilities:Payable:<invoiceno>
      iv. invoiced expense from Liabilities:Payable:<invoiceno> to
          Expenses:Widgets.
       Here (i) and (ii) are generated by a script applied to PayPal
       CSV export, without reference to other transactions in the
       journal.  Editing them by hand is out of the question.

    I realize that this may expose ledger to FIFO/LIFO questions,
    which ledger doesn't address -- e.g., if I receive two 10000 JPY
    invoices at different exchange rates, and then pay out 15000 JPY
    at a third exchange rate, how much gain/loss should I report?  But
    at the moment I think that this scenario doesn't actually come up
    in my records, so I would be satisfied without finding a way to
    talk ledger into understanding FIFO or LIFO rules.


[*] Actually it's more like `USD 109.672 JPY' and `USD 104.84925 JPY';
I manually computed the reciprocal so that ledger treats USD as the
primary commodity.  It would be nice if I didn't have to do that.  But
that's a separate issue.

-- 

--- 
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].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/ledger-cli/20200328060039.21DE260A4B%40jupiter.mumble.net.

Reply via email to