One of the things which stalled Ledger development recently is that I'd never
found a truly satisfying way to handle the "commodity pricing problem".  That
is, the current day value of a commodity can mean different things to
different people, depending on the accounts involved, the commodities, the
nature of the transactions, etc.

After experimenting with several different concepts and syntaxes, I found none
of them were either satisfying or general enough.  My one attempt at providing
"fixated prices" was too specific, and too inelegant for many usage patterns.

This morning, however, I think I've finally cracked this nut; and in a way
which fits harmoniously into the Ledger architecture as if it were meant to be
there all along...

Here's how the new scheme will work: When a user specifies '-V', or '-X COMM',
they are requesting that some or all of the commodities in their Ledger file
be valuated as of today (or whatever --now is set to).  But what does such a
valuation mean?  This meaning shall be governed by the presence of a "VALUE"
metadata property, whose content is an expression used to compute that value.

If no VALUE property is specified, each posting is assumed to have a default,
as if you'd specified a global, automated transaction as follows:

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

This definition emulates the present day behavior of -V and -X (in the case of
-X, the requested commodity is passed via the string 'exchange' above).

One thing many people have wanted to do is to fixate the valuation of old
European currencies in terms of the Euro after a certain date:

  = expr commodity == "DM"
    ; VALUE:: date < [Jun 2008] ? market(amount, date, exchange) : 1.44 EUR

This says: If --now is some old date, use market prices as they were at that
time; but if --now is past June 2008, use a fixed price for converting Deutsch
Mark to Euro.

Or how about never re-valuating commodities used in Expenses, since they
cannot have a different future value:

  = /^Expenses:/
    ; VALUE:: market(amount, post.date, exchange)

This says the future valuation is the same as the valuation at the time of
posting.  post.date equals the posting's date, while just 'date' is the value
of --now (defaults to today).

Or how about valuating miles based on a reimbursement rate during a specific
time period:

  = expr commodity == "miles" and date >= [2007] and date < [2008]
    ; VALUE:: market($1.05, date, exchange)

In this case, miles driven in 2007 will always be valuated at $1.05 each.  If
you use -X EUR to expressly request all amounts in Euro, Ledger shall convert
$1.05 to Euro by whatever means are appropriate for dollars.

Note that you can have a valuation expression specific to a particular posting
or transaction, by overriding these general defaults using specific metadata:

  2010-12-26 Example
      Expenses:Food                $20
      ; Just to be silly, always valuate *these* $20 as 30 DM, no matter what
      ; the user asks for with -V or -X
      ; VALUE:: 30 DM
      Assets:Cash

This example demonstrates that your VALUE expression should be as symbolic as
possible, using terms like 'amount' and 'date', rather than specific amounts
and dates.  Also, you should pass the amount along to the function 'market' so
it can be further revalued if the user has asked for a specific currency.

Or, if it better suits your accounting, you can be less symbolic, which allows
you to report most everything in EUR if you use -X EUR, except for certain
accounts or postings which should always be valuated in another currency.  For
example:

  = /^Assets:Brokerage:CAD$/
    ; Always report the value of commodities in this account in terms of
    ; present day dollars, despite what was asked for on the command-line
    ; VALUE:: market(amount, date, '$')

I think this scheme, of using predicated value expressions which can be
generalized in automated transactions, and made specific via transaction and
posting-based metadata, provides sufficient flexibility to express most of the
use cases which have occurred on this topic.

Comments on the design welcome, as I haven't begun coding yet.  Feel free to
pose scenarios, and I'll try to model them for you.

John

Reply via email to