Understanding transactions

1,321 views
Skip to first unread message

John Wiegley

unread,
Mar 10, 2012, 2:51:37 AM3/10/12
to ledge...@googlegroups.com
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

Gabriel Kerneis

unread,
Mar 10, 2012, 3:40:09 AM3/10/12
to ledge...@googlegroups.com
Hi John,

thanks for the explanations, great piece of documentation. A few remarks and
questions.

On Sat, Mar 10, 2012 at 01:51:37AM -0600, John Wiegley wrote:
> 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

Is this a spurious * on the first line?

> 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:

What happens if it doesn't balance?

> 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".

Great, this part is totally new to me. Much clearer now.

> 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.

Is it {$50.00} or {$5.00}? You lost me there.

> 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.

So what is the exact rule when both sides of an @ don't match? Here we have a
$250 difference, and this difference is added to the balance of the transaction
if and only if I use the lot-price annotation { } (or the shorthand {{ }})?

> Plus, it comes with dangers. This works fine:
>
> 2012-04-10 My Broker
> Assets:Brokerage 10 AAPL @ $50.00
> Assets:Brokerage:Cash $750.00

I don't understand how this can balance. Should it be $500.00 instead? (I
believe it's not a typo since you reuse the example several times below).

> 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

Does ledger check that the dates match (ie can I use the lot date as some kind
of inventory tracking)?

> # Lot value expressions

I skipped that part, I feel I need to understand the rest before diving into it.

Best,
--
Gabriel

djp

unread,
Mar 10, 2012, 3:45:04 AM3/10/12
to ledge...@googlegroups.com
On Saturday, 10 March 2012 02:51:37 UTC-5, John Wiegley wrote:
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.

TODO: I ran out of steam.

John


wow John, thank you! this makes a HUGE difference (more please ;-)

Craig Earls

unread,
Mar 10, 2012, 10:27:21 AM3/10/12
to ledge...@googlegroups.com
I will make sure this gets into the docs ASAP.  Along with the other recent long posting about features and behavior.


On Sat, Mar 10, 2012 at 00:51, John Wiegley <jwie...@gmail.com> wrote:
The following mini-doc attempts to cover every syntactic corner of the
Ledger transaction syntax.  If I've missed anything, please let me know.




--
Craig, Corona De Tucson, AZ
enderw88.wordpress.com

John Wiegley

unread,
Mar 10, 2012, 9:21:35 PM3/10/12
to ledge...@googlegroups.com
>>>>> Gabriel Kerneis <kerneis-klhGwnj...@public.gmane.org> writes:

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

> Is this a spurious * on the first line?

Ah, yes, thank you for catching that. Craig, can you incorporate that fix?

>> 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:

> What happens if it doesn't balance?

The transaction will result in a balancing error.

>> 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.

> Is it {$50.00} or {$5.00}? You lost me there.

Oops, it should be {$50.00}, you are right. The @ goes to {} just as @@ goes
to {{}}.

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

> So what is the exact rule when both sides of an @ don't match? Here we have
> a $250 difference, and this difference is added to the balance of the
> transaction if and only if I use the lot-price annotation { } (or the
> shorthand {{ }})?

Yes. Without the pricing annotation, Ledger doesn't know there is a
difference between what you paid in the past, and what you are paying now. It
is this difference which it accumulates in either Equity:Capital Gains or
Equity:Capital Losses (those strings soon to be made configurable).

>> Plus, it comes with dangers. This works fine:
>>
>> 2012-04-10 My Broker Assets:Brokerage 10 AAPL @ $50.00
>> Assets:Brokerage:Cash $750.00

> I don't understand how this can balance. Should it be $500.00 instead? (I
> believe it's not a typo since you reuse the example several times below).

Sorry, in this case it should be $500.00. Guess it got too late for me. :)

When this document gets converted into Texinfo format by Craig, we'll add
markers to turn all these examples into regression tests, to prove that each
example does what I think it should.

> Does ledger check that the dates match (ie can I use the lot date as some
> kind of inventory tracking)?

No. The only way to find a discrepancy is to add --lot-dates to a balance
report and look and see what results. There is no case in Ledger where it
ensures that transactions balance against *other* transactions. You can
balance the postings within a transaction, or you can balance an amount
against a current account total, but you can say that transaction B should
match the details of some earlier transaction A.

>> # Lot value expressions

> I skipped that part, I feel I need to understand the rest before diving into
> it.

Don't blame you. :) That feature is more to provide infrastructure. It gets
used behind the scenes by -H and a few other features now. Plus, it's an
access point into the valuation logic for those who have the need. I'm
guessing 99% of people won't use it, but I'm glad it's there because Ledger
itself now uses it!

John

Simon Michael

unread,
Mar 11, 2012, 5:01:47 PM3/11/12
to ledge...@googlegroups.com
Awesome docs, John!

I think https://github.com/jwiegley/ledger/commits/next/doc/ledger3.texi will show when they land on the site.
(Thanks Craig!)

thierry

unread,
Mar 14, 2012, 4:24:09 PM3/14/12
to Ledger


On Mar 10, 8:51 am, John Wiegley <jwieg...@gmail.com> wrote:
> ## 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.

Is that really important? I have 10% of my transactions with "top"
posting as source, and "final" posting as target. And IMHO, I do
prefer that source is first, and target is last. Can I safely ignore
this ledger convention?
I realize also that I am never using -V, but only -X, and this may be
the explanation.

John Wiegley

unread,
Mar 15, 2012, 12:58:12 AM3/15/12
to ledge...@googlegroups.com
>>>>> thierry <thierry.daucou...@public.gmane.org> writes:

> Is that really important? I have 10% of my transactions with "top" posting
> as source, and "final" posting as target. And IMHO, I do prefer that source
> is first, and target is last. Can I safely ignore this ledger convention? I
> realize also that I am never using -V, but only -X, and this may be the
> explanation.

It's not important, it only affects the behavior of -V. -V tries to be a
shorthand for "show me values in terms of the commodities I used to purchase
things with". This was the best heuristic I could come up with.

John

Reply all
Reply to author
Forward
0 new messages