Plain text accounting

plaintextaccounting.org has a nice overview of the topic.

This is part of the general accounting for programmers.

Plain Text Accounting formats

What is common is that this is a list of directives in one or more text files. There are a number of directives. The order of the directives is not that important.

There are a number of definitions:

EBNF format

This is a partial description of Beancounts plain text journal format:

journal ::= entry*
entry ::= comment | transaction
comment ::= WS* ";" AllChar* EOL
transaction ::= header postings
postings ::= posting posting posting*

directive ::= value-date {^knowledge-date} {* transaction | 'open' open-directive | 'balance' balance-directive}
blank-line ::= \n;
header ::= value white_space id  \n;
value-date ::= (full-date | date-time);
knowledge-date ::= (full-date | date-time);
white-space ::= ? white space characters ? ;
posting = account {asset-class};
balance-posting = account;
id = string;
comment = string;
string ::= '"' AllChar* '"'


account = (`Assets` | `Liabilities` | `Equity` | `Income` | 'Expenses') : name
name = TEXT | TEXT : name

full-date       = date-fullyear "-" date-month "-" date-mday
full-time       = partial-time time-offset

date-time       = full-date "T" full-time

The date time format is more fully documented in RFC-3339 and I had an initial version here for project Luca.

Chart of accounts

An account has the following syntax

account = {type} name {subaccount}
subaccount = ":" name {subaccount}

Directive types

A directive is one or more lines:

directive = date type

Type Beancount Hledger
Posting Pure txn,*,! Info rich
Comment ; Pure comment ;,# may contain notes
unknown Ignores
open account be opened
close Optional close
commodity
balance Balance assertion folded into posting leg
pad Auto calculate balances
note
document Neat link to a document
price Parameter price
event
query
custom For option extension

There is also metadata and options.

Posting

A posting is a set of posting legs that balance and happen at a single point in time.

In beancount a posting is called a transaction.

A posting consists of a posting instruction description followed by posting legs.

The posting directive is a multi line directive which must be kept together. Some reordering eg of the posting legs is possible without information being lost.

Posting leg

This is indented to denote that it belongs to the preceeding posting instruction.

Comment

In beancount all text specified as comment is ignored. In hledger further parsing may reveal more information

Open

Beancount requires you to have an open account directive before an account is used. However you can infer the accounts

Account life is OPEN -> CLOSED However this is not the only state transition possible eg

Close

Balance

An account is s series of postings and at any one time you have a balance on that account.

A complete list of balances has the identical information to a complete list of postings. There is cross over between a database value (balance) as against the transaction log (postings) which contain similar information.

However balances have a couple of useful properties:

Kafka also has the same characteristics in that a stream of changes is equivalent to the current state.

Balance assertions

Coin the goledger has added in balance transactions to a posting leg:

2024/01/02 AMZNMktplace ON 29 DEC BCC
  Unbalanced               34.20 GBP
  Assets:Bank:H3Personal  -34.20 GBP = 224.69 GBP

This is then used in abbreviated form for instance in Ledger:

2020-01-01 Reconciliation
    Assets:Cash at Bank  $0 = $100

And in beancount:

2012-02-04 balance Assets:CA:Bank:Checking    417.61 CAD

The Beancount syntax is superior as the balance assertions are clear and distinct from the postings and order of postings. For balance reconciliation it is also superior. When doing the accounting for a customer the bank record is one of the independent bits of evidence so the reconciliation is important.

Ordering of directives

Hledger recommends that directives should be ordered in date order. A unique ordering is important if you would like to have a consistent hash that is the same if the order of the directives is changed or the comments are edited.

My plain text accounting format

Proposed Journal Entries

Aim to write journal entries like this:

2025-01-01 * Equity » 15 » Cash

Golang ledger implementations

This is an abstract and an enhancement of the PTA apps table but only focused on golang implementations.

As of 2024-11-21

Name Start Last Release Contributors Stars Forks Comment
Ledger (Go) 2017 2024 12 462 43 Single currency
knut 2020 2024 3 58 10 Multicurrency, accruals
tn47 goledger 2017 2018 1 35 13 Float64?
Coin 2019 2024 2 10 0 big Int

Ledger (Go)

Has a manual. Much faster than the other ledger implementations (10 to 100 times) on its own benchmarks.

Representation

Uses int64 for numbers with a fixed 0.001 resolution.

A book is listed as a collection of transactions.

knut

goledger

coin

Representation

Uses bigint plus variable number of decimal places

2025

© 2018 - 2025 · Bytestone Blog · Theme Simpleness Powered by Hugo ·