The following mini-doc attempts to cover every syntactic corner of the
Ledger transaction syntax.  If I've missed anything, please let me know.

Note that this is a subset of all the syntax allowed in a journal file.  I
haven't covered directives here or file-level comments.

John

# Basic format

The most basic form of transaction is:

    2012-03-10 KFC
        Expenses:Food                $20.00
        Assets:Cash                 $-20.00

This transaction has a date, a payee or description, a target account (the
first posting), and a source account (the second posting).  Each posting
specifies what action is taken related to that account.

## Multiple postings

A transaction can have any number of postings:

    2012-03-10 KFC
        Expenses:Food                $20.00
        Assets:Cash                 $-10.00
        Liabilities:Credit          $-10.00

# Eliding amounts

The first thing you can do to make things easier is elide amounts.  That is,
if exactly one posting has no amount specified, Ledger will infer the inverse
of the other postings' amounts:

    2012-03-10 KFC
        Expenses:Food                $20.00
        Assets:Cash                 $-10.00
        Liabilities:Credit                   ; same as specifying $-10

## Elision with multiple commodities

If the other postings use multiple commodities, Ledger will copy the empty
posting N times and fill in the negated values of the various commodities:

    2012-03-10 KFC
        Expenses:Food                $20.00
        Expenses:Tips                 $2.00
        Assets:Cash              EUR -10.00
        Assets:Cash              GBP -10.00
        Liabilities:Credit

This transaction is identical to writing:

    2012-03-10 KFC
        Expenses:Food                $20.00
        Expenses:Tips                 $2.00
        Assets:Cash              EUR -10.00
        Assets:Cash              GBP -10.00
        Liabilities:Credit          $-22.00
        Liabilities:Credit        EUR 10.00
        Liabilities:Credit        GBP 10.00

# Auxiliary dates

You can associate a second date with a transaction by following the primary
date with an equals sign:

    2012-03-10=2012-03-08 KFC
        Expenses:Food                $20.00
        Assets:Cash                 $-20.00

What this auxiliary date means is entirely up to you.  The only use Ledger has
for it is that if you specify --aux-date, then all reports and calculations
(including pricing) will use the aux date as if it were the primary date.

# Codes

A transaction can have a textual "code".  This has no meaning and is only
displayed by the print command.  Checking accounts often use codes like DEP,
XFER, etc., as well as check numbers.  This is to give you a place to put
those codes:

    2012-03-10 (#100) KFC
        Expenses:Food                $20.00
        Assets:Checking

# Transaction state

A transaction can have a "state": cleared, pending, or uncleared.  The default
is uncleared.  To mark a transaction cleared, put a * before the payee, and
after date or code:

    2012-03-10 * KFC
        Expenses:Food                $20.00
        Assets:Cash

To mark it pending, use a !:

    2012-03-10 ! KFC
        Expenses:Food                $20.00
        Assets:Cash

What these mean is entirely up to you.  The --cleared option will limits to
reports to only cleared items, while --uncleared shows both uncleared and
pending items, and --pending shows only pending items.

I use cleared to mean that I've reconciled the transaction with my bank
statement, and pending to mean that I'm in the middle of a reconciliation.

## Posting state

When you clear a transaction, that's really just shorthand for clearing all of
postings.  That is:

    2012-03-10 * KFC
        Expenses:Food                $20.00
        Assets:Cash

Is the same as writing:

    2012-03-10 KFC
        * Expenses:Food                $20.00
        * Assets:Cash

You can mark individual postings as cleared or pending, in case one "side" of
the transaction has cleared, but the other hasn't yet:

    2012-03-10 * KFC
        Liabilities:Credit            $100.00
        * Assets:Checking

# Transaction notes

After the payee, and after at least one tab or two spaces (or a space and a
tab) [Ledger calls this a "hard separator"], you may introduce a note about
the transaction using the ; character:

    2012-03-10 * KFC                ; yum, chicken...
        Expenses:Food                $20.00
        Assets:Cash

Notes can also appear on the next line, so long as that line begins with
whitespace:

    2012-03-10 * KFC                ; yum, chicken...
        ; and more notes...
        Expenses:Food                $20.00
        Assets:Cash

    2012-03-10 * KFC
        ; just these notes...
        Expenses:Food                $20.00
        Assets:Cash

## Posting notes

A transaction notes is shared by all its postings.  This becomes significant
when querying for metadata (see below).  To specify that a note belongs only
to one posting, place it after a hard separator after the amount, or on its
own line preceded by whitespace:

    2012-03-10 * KFC
        Expenses:Food                $20.00  ; posting #1 note
        Assets:Cash
          ; posting #2 note, extra indentation is optional

# Metadata

One of Ledger's more powerful features is the ability to associate typed
metadata with postings and transactions (by which I mean all of a
transaction's postings).  This metadata can be queried, displayed, and used in
calculations.

The are two forms of metadata: tags and tag/value pairs.

## Metadata tags

To tag an item, put any word not containing whitespace between two colons:

    2012-03-10 * KFC
        Expenses:Food                $20.00
        Assets:Cash
          ; :TAG:

You can gang up multiple tags by sharing colons:

    2012-03-10 * KFC
        Expenses:Food                $20.00
        Assets:Cash
          ; :TAG1:TAG2:TAG3:
          

## Metadata values

To associate a value with a tag, use the syntax "Key: Value", where the value
can be any string of characters.  Whitespace is needed after the colon, and
cannot appear in the Key:

    2012-03-10 * KFC
        Expenses:Food                $20.00
        Assets:Cash
          ; MyTag: This is just a bogus value for MyTag
          
### Typed metadata

If a metadata tag ends in ::, it's value will be parsed as a value expression
and stored internally as a value rather than as a string.  For example,
although I can specify a date textually like so:

    2012-03-10 * KFC
        Expenses:Food                $20.00
        Assets:Cash
          ; AuxDate: 2012/02/30
          
This date is just a string, and won't be parsed as a date unless its value is
used in a date-context (at which time the string is parsed into a date
automatically every time it is needed as a date).  If on the other hand I
write this:

    2012-03-10 * KFC
        Expenses:Food                $20.00
        Assets:Cash
          ; AuxDate:: [2012/02/30]

Then it is parsed as a date only once, and during parsing of the journal file,
which would let me know right away that it is an invalid date.

# Virtual postings

Ordinary, the amounts of all postings in a transaction must balance to zero.
This is non-negotiable.  It's what double-entry accounting is all about!  But
there are some tricks up Ledger's sleeve...

You can use virtual accounts to transfer amounts to an account on the sly,
bypassing the balancing requirement.  The trick is that these postings are not
considered "real", and can be removed from all reports using --real.

To specify a virtual account, surround the account name with parentheses:

    2012-03-10 * KFC
        Expenses:Food                $20.00
        Assets:Cash
        (Budget:Food)               $-20.00
        
If you want, you can state that virtual postings *should* balance against
one or more other virtual postings by using brackets (which look "harder")
rather than parentheses:

    2012-03-10 * KFC
        Expenses:Food                $20.00
        Assets:Cash
        [Budget:Food]               $-20.00
        [Equity:Budgets]             $20.00

# Expression amounts

An amount is usually a numerical figure with an (optional) commodity, but it
can also be any value expression.  To indicate this, surround the amount
expression with parentheses:

    2012-03-10 * KFC
        Expenses:Food      ($10.00 + $20.00)  ; Ledger adds it up for you
        Assets:Cash

# Balance verification

If at the end of a posting's amount (and after the cost too, if there is one)
there is an equals sign, then Ledger will verify that the total value for that
account as of that posting matches the amount specified.

There are two forms of this features: balance assertions, and balance
assignments.

## Balance assertions

A balance assertion has this general form:

    2012-03-10 KFC
        Expenses:Food                $20.00
        Assets:Cash                 $-20.00 = $500.00

This simply asserts that after subtracting $20.00 from Assets:Cash, that the
resulting total matches $500.00.  If not, it is an error.

## Balance assignments

A balance assignment has this form:

    2012-03-10 KFC
        Expenses:Food                $20.00
        Assets:Cash                         = $500.00

This sets the amount of the second posting to whatever it would need to be for
the total in Assets:Cash to be $500.00 after the posting.  If the resulting
amount is not $-20.00 in this case, it is an error.

## Tip: Resetting a balance

Say your book-keeping has gotten a bit out of date, and your Ledger balance no
longer matches your bank balance.  You can create an adjustment transaction
using balance assignments:

    2012-03-10 Adjustment
        Assets:Cash                         = $500.00
        Equity:Adjustments

Since the second posting is also null, it's value will become the inverse of
whatever amount is generated for the first posting.

This is the only time in ledger when more than one posting's amount may be
empty -- and then only because it's not true empty, it is indirectly provided
by the balance assignment's value.

## Tip: Balancing transactions

As a consequence of all the above, consider the following transaction:

    2012-03-10 My Broker
        [Assets:Brokerage]            = 10 AAPL

What this says is: set the amount of the posting to whatever value is needed
so that Assets:Brokerage contains 10 AAPL.  Then, because this posting must
balance, ensure that its value is zero.  This can only be true if
Assets:Brokerage does indeed contain 10 AAPL at that point in the input file.

A balanced virtual transaction is used simply to indicate to Ledger that this
is not a "real" transaction.  It won't appear in any reports anyway (unless
you use a register report with --empty).

# Posting costs

When you transfer a commodity from one account to another, sometimes it get
transformed during the transaction.  This happens when you spend money on gas,
for example, which transforms dollars into gallons of gasoline, or dollars
into stocks in a company.

In those cases, Ledger will remember the "cost" of that transaction for you,
and can use it during reporting in various ways.  Here's an example of a stock
purchase:

    2012-03-10 My Broker
        Assets:Brokerage             10 AAPL
        Assets:Brokerage:Cash       $-500.00

This is different from transferring 10 AAPL shares from one account to
another, in this case you are *exchanging* one commodity for another.  The
resulting posting cost is $50.00 per share.

# Explicit posting costs

You can make any posting's cost explicit using the @ symbol after the amount
or amount expression:

    2012-03-10 My Broker
        Assets:Brokerage             10 AAPL @ $50.00
        Assets:Brokerage:Cash       $-500.00

When you do this, since Ledger can now figure out the balancing amount from
the first posting's cost, you can elide the other amount:

    2012-03-10 My Broker
        Assets:Brokerage             10 AAPL @ $50.00
        Assets:Brokerage:Cash

## Primary and secondary commodities

It is a general convention within Ledger that the "top" postings in a
transaction contain the target accounts, while the final posting contains the
source account.  Whenever a commodity is exchanged like this, the commodity
moved to the target account is considered "secondary", while the commodity
used for purchasing and tracked in the cost is "primary".

Said another way, whenever Ledger sees a posting cost of the form "AMOUNT @
AMOUNT", the commodity used in the second amount is marked "primary".

The only meaning a primary commodity has is that -V flag will never convert a
primary commodity into any other commodity.  -X still will, however.

# Posting cost expressions

Just as you can have amount expressions, you can have posting expressions:

    2012-03-10 My Broker
        Assets:Brokerage             10 AAPL @ ($500.00 / 10)
        Assets:Brokerage:Cash

You can even have both:

    2012-03-10 My Broker
        Assets:Brokerage             (5 AAPL * 2) @ ($500.00 / 10)
        Assets:Brokerage:Cash

# Total posting costs

The cost figure following the @ character specifies the *per-unit* price for
the commodity being transferred.  If you'd like to specify the total cost
instead, use @@:

    2012-03-10 My Broker
        Assets:Brokerage             10 AAPL @@ $500.00
        Assets:Brokerage:Cash

Ledger reads this as if you had written:

    2012-03-10 My Broker
        Assets:Brokerage             10 AAPL @ ($500.00 / 10)
        Assets:Brokerage:Cash

# Virtual posting costs

Normally whenever a commodity exchange like this happens, the price of the
exchange (such as $50 per share of AAPL, above) is recorded in Ledger's
internal price history database.  To prevent this from happening in the case
of an exceptional transaction, surround the @ or @@ with parentheses:

    2012-03-10 My Brother
        Assets:Brokerage            1000 AAPL (@) $1
        Income:Gifts Received

# Commodity prices

When a transaction occurs that exchange one commodity for another, Ledger
records that commodity price not only within its internal price database, but
also attached to the commodity itself.  Usually this fact remains invisible to
the user, unless you turn on --lot-prices to show these hidden price figures.

For example, consider the stock sale given above:

    2012-03-10 My Broker
        Assets:Brokerage             10 AAPL @ $50.00
        Assets:Brokerage:Cash

The commodity transferred into Assets:Brokerage is not actually 10 AAPL, but
rather 10 AAPL {$5.00}.  The figure in braces after the amount is called the
"lot price".  It's Ledger's way of remembering that this commodity was
transferred through an exchange, and that $5.00 was the price of that
exchange.

This becomes significant if you later sell that commodity again.  For example,
you might write this:

    2012-04-10 My Broker
        Assets:Brokerage:Cash
        Assets:Brokerage            -10 AAPL @ $75.00

And that would be perfectly fine, but how do you track the capital gains on
the sale?  It could be done with a virtual posting:

    2012-04-10 My Broker
        Assets:Brokerage:Cash
        Assets:Brokerage            -10 AAPL @ $75.00
        (Income:Capital Gains)      $-250.00

But this gets messy since capital gains income is very real, and not quite
appropriate for a virtual posting.

Instead, if you reference that same hidden price annotation, Ledger will
figure out that the price of the shares you're selling, and the cost you're
selling them at, don't balance:

    2012-04-10 My Broker
        Assets:Brokerage:Cash       $750.00
        Assets:Brokerage            -10 AAPL {$50.00} @ $75.00

This transaction will fail because the $250.00 price difference between the
price you bought those shares at, and the cost you're selling them for, does
not match.  The lot price also identifies which shares you purchased on that
prior date.

## Total commodity prices

As a shorthand, you can specify the total price instead of the per-share
price in doubled braces.  This goes well with total costs, but is not required
to be used with them:

    2012-04-10 My Broker
        Assets:Brokerage:Cash       $750.00
        Assets:Brokerage            -10 AAPL {{$500.00}} @@ $750.00
        Income:Capital Gains       $-250.00

It should be noted that this is a convenience only for cases where you buy and
sell whole lots.  The {{$500.00}} is *not* an attribute of commodity, whereas
{$5.00} is.  In fact, when you write {{$500.00}}, Ledger just divides that
value by 10 and sees {$50.00}.  So if you use the print command to look at
this transaction, you'll see the single form in the output.  The double price
form is a shorthand only.

Plus, it comes with dangers.  This works fine:

    2012-04-10 My Broker
        Assets:Brokerage            10 AAPL @ $50.00
        Assets:Brokerage:Cash       $750.00

    2012-04-10 My Broker
        Assets:Brokerage:Cash       $375.00
        Assets:Brokerage            -5 AAPL {$50.00} @@ $375.00
        Income:Capital Gains       $-125.00

    2012-04-10 My Broker
        Assets:Brokerage:Cash       $375.00
        Assets:Brokerage            -5 AAPL {$50.00} @@ $375.00
        Income:Capital Gains       $-125.00

But this does not do what you might expect:

    2012-04-10 My Broker
        Assets:Brokerage            10 AAPL @ $50.00
        Assets:Brokerage:Cash       $750.00

    2012-04-10 My Broker
        Assets:Brokerage:Cash       $375.00
        Assets:Brokerage            -5 AAPL {{$500.00}} @@ $375.00
        Income:Capital Gains       $-125.00

    2012-04-10 My Broker
        Assets:Brokerage:Cash       $375.00
        Assets:Brokerage            -5 AAPL {{$500.00}} @@ $375.00
        Income:Capital Gains       $-125.00

And in cases where the amounts do not divide into whole figure and must be
rounded, the capital gains figure could be off by a cent.  Use with caution.

# Prices vs. costs

Because lot pricing provides enough information to infer the cost, the
following two transactions are equivalent:

    2012-04-10 My Broker
        Assets:Brokerage            10 AAPL @ $50.00
        Assets:Brokerage:Cash       $750.00

    2012-04-10 My Broker
        Assets:Brokerage            10 AAPL {$50.00}
        Assets:Brokerage:Cash       $750.00

However, note that what you see in some reports may differ, for example in the
print report.  Functionally, however, there is no difference, and neither the
register nor the balance report are sensitive to this difference.

# Fixated prices

If you buy a stock last year, and ask for its value today, Ledger will consult
its price database to see what the most recent price for that stock is.  You
can short-circuit this lookup by "fixing" the price at the time of a
transaction.  This is done using {=AMOUNT}:

    2012-04-10 My Broker
        Assets:Brokerage            10 AAPL {=$50.00}
        Assets:Brokerage:Cash       $750.00

These 10 AAPL will now always be reported as being worth $50, no matter what
else happens to the stock in the meantime.

Fixated prices are a special case of using lot valuation expressions (see
below) to fix the value of a commodity lot.

## Fixated costs

Since price annotations are costs are largely interchangeable and a matter of
preference, there is an equivalent syntax for specified fixated prices by way
of the cost:

    2012-04-10 My Broker
        Assets:Brokerage            10 AAPL @ =$50.00
        Assets:Brokerage:Cash       $750.00

This is the same as the previous transaction, with the same caveats found in
the section "Prices vs. costs".

# Lot dates

In addition to lot prices, you can specify lot dates and reveal them with
--lot-dates.  Other than that, however, they have no special meaning to
Ledger.  They are specified after the amount in square brackets (the same way
that dates are parsed in value expressions):

    2012-04-10 My Broker
        Assets:Brokerage:Cash       $375.00
        Assets:Brokerage            -5 AAPL {$50.00} [2012-04-10] @@ $375.00
        Income:Capital Gains       $-125.00

# Lot notes

You can also associate arbitrary notes for your own record keeping in
parentheses, and reveal them with --lot-notes.  One caveat is that the note
cannot begin with an @ character, as that would indicate a virtual cost:

    2012-04-10 My Broker
        Assets:Brokerage:Cash       $375.00
        Assets:Brokerage            -5 AAPL {$50.00} [2012-04-10] (Oh my!) @@ 
$375.00
        Income:Capital Gains       $-125.00

You can any combination of lot prices, dates or notes, in any order.  They are
all optional.

To show all lot information in a report, use --lots.

# Lot value expressions

Normally when you ask Ledger to display the values of commodities held, it
uses a value expression called "market" to determine the most recent value
from its price database -- even downloading prices from the Internet, if -Q
was specified and a suitable "getquote" script is found on your system.

However, you can override this valuation logic by providing a commodity
valuation expression in doubled parentheses.  This expression must result in
one of two values: either an amount to always be used as the per-share price
for that commodity; or a function taking three argument which is called to
determine that price.

If you use the functional form, you can either specify a function name, or a
lambda expression.  Here's a function that yields the price as $10 in whatever
commodity is being requested:

    define ten_dollars(s, date, t) = market($10, date, t)

I can now use that in a lot value expression as follows:

    2012-04-10 My Broker
        Assets:Brokerage:Cash       $375.00
        Assets:Brokerage            -5 AAPL {$50.00} ((ten_dollars)) @@ $375.00
        Income:Capital Gains       $-125.00

Alternatively, I could do the same thing without pre-defining a function by
using a lambda expression taking three arguments:

    2012-04-10 My Broker
        A:B:Cash       $375.00
        A:B     -5 AAPL {$50.00} ((s, d, t -> market($10, date, t))) @@ $375.00
        Income:Capital Gains       $-125.00

The arguments passed to these functions have the following meaning:

    source - The source commodity string, or an amount object.  If it is a
      string, the return value must be an amount representing the price of the
      commodity identified by that string (example: "$").  If it is an amount,
      return the value of that amount as a new amount (usually calculated as
      commodity price * source amount).

    date - The date to use for determining the value.  If null, it means no
      date was specified, which can mean whatever you want it to mean.

    target - If not null, a string representing the desired target commodity
      that the commodity price, or repriced amount, should be valued in.  Note
      that this string can be a comma-separated list, and that some or all of
      the commodities in that list may be suffixed with an exclamation mark,
      to indicate what is being desired.

In most cases, it is simplest to either use explicit amounts in your valuation
expressions, or just pass the arguments down to market after modifying them to
suit your needs.

# Automated transactions

An automated transaction is a special kind of transaction which adds its
postings to other transactions any time one of that other transactions'
postings matches its predicate.  The predicate uses the same query syntax as
the Ledger command line.

Consider this posting:

    2012-03-10 KFC
        Expenses:Food                $20.00
        Assets:Cash

If I write this automated transaction before it in the file:

    = expr true
        Foo                          $50.00
        Bar                         $-50.00

Then the first transaction will be modified during parsing as if I'd written
this:

    2012-03-10 KFC
        Expenses:Food                $20.00
        Foo                          $50.00
        Bar                         $-50.00
        Assets:Cash                 $-20.00
        Foo                          $50.00
        Bar                         $-50.00

Despite this fancy logic, automated transactions themselves follow most of the
same rules as regular transactions: their postings must balance (unless you
use a virtual posting), you can have metadata, etc.

One thing you cannot do, however, is elide amounts in an automated
transaction.

## Amount multipliers

As a special case, if an automated transaction's posting's amount (phew) has
no commodity, it is taken as a multiplier upon the matching posting's cost.
For example:

    = expr true
        Foo                           50.00
        Bar                          -50.00

    2012-03-10 KFC
        Expenses:Food                $20.00
        Assets:Cash

Then the latter transaction turns into this during parsing:

    2012-03-10 KFC
        Expenses:Food                $20.00
        Foo                        $1000.00
        Bar                       $-1000.00
        Assets:Cash                 $-20.00
        Foo                        $1000.00
        Bar                       $-1000.00

## Accessing the matching posting's amount

If you use an amount expression for an automated transaction's posting, that
expression has access to all the details of the matched posting.  For example,
you can refer to that posting's amount using the "amount" value expression
variable:

    = expr true
        (Foo)                  (amount * 2)  ; same as just "2" in this case

    2012-03-10 KFC
        Expenses:Food                $20.00
        Assets:Cash

This becomes:

    2012-03-10 KFC
        Expenses:Food                $20.00
        (Foo)                        $40.00
        Assets:Cash                 $-20.00
        (Foo)                       $-40.00

## Referring to the matching posting's account

Sometimes want to refer to the account that matched in some way within the
automated transaction itself.  This is done by using the string $account,
anywhere within the account part of the automated posting:

    = food
        (Budget:$account)                10

    2012-03-10 KFC
        Expenses:Food                $20.00
        Assets:Cash

Becomes:

    2012-03-10 KFC
        Expenses:Food                $20.00
        (Budget:Expenses:Food)      $200.00
        Assets:Cash                 $-20.00

## Applying metadata to every matched posting

If the automated transaction has a transaction note, that note is copied
(along with any metadata) to every posting that matches the predicate:

    = food
        ; Foo: Bar
        (Budget:$account)                10

    2012-03-10 KFC
        Expenses:Food                $20.00
        Assets:Cash

Becomes:

    2012-03-10 KFC
        Expenses:Food                $20.00
          ; Foo: Bar
        (Budget:Expenses:Food)      $200.00
        Assets:Cash                 $-20.00

## Applying metadata to the generated posting

If the automated transaction's posting has a note, that note is carried to the
generated posting within the matched transaction:

    = food
        (Budget:$account)                10
          ; Foo: Bar

    2012-03-10 KFC
        Expenses:Food                $20.00
        Assets:Cash

Becomes:

    2012-03-10 KFC
        Expenses:Food                $20.00
        (Budget:Expenses:Food)      $200.00
          ; Foo: Bar
        Assets:Cash                 $-20.00

This is slightly different from the rules for regular transaction notes, in
that an automated transaction's note does not apply to every posting within
the automated transaction itself, but rather to every posting it matches.

## State flags

Although you cannot mark an automated transaction as a whole as cleared or
pending, you can mark its postings with a * or ! before the account name, and
that state flag gets carried to the generated posting.

# Periodic transactions

TODO: I ran out of steam.

John

Reply via email to